/** * Revalidates the fields cache * * @param header the header */ static void _dbus_header_cache_revalidate (DBusHeader *header) { DBusTypeReader array; DBusTypeReader reader; int i; i = 0; while (i <= DBUS_HEADER_FIELD_LAST) { header->fields[i].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT; ++i; } _dbus_type_reader_init (&reader, header->byte_order, &_dbus_header_signature_str, FIELDS_ARRAY_SIGNATURE_OFFSET, &header->data, FIELDS_ARRAY_LENGTH_OFFSET); _dbus_type_reader_recurse (&reader, &array); while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID) { DBusTypeReader sub; DBusTypeReader variant; unsigned char field_code; _dbus_type_reader_recurse (&array, &sub); _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_BYTE); _dbus_type_reader_read_basic (&sub, &field_code); /* Unknown fields should be ignored */ if (field_code > DBUS_HEADER_FIELD_LAST) goto next_field; _dbus_type_reader_next (&sub); _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_VARIANT); _dbus_type_reader_recurse (&sub, &variant); _dbus_header_cache_one (header, field_code, &variant); next_field: _dbus_type_reader_next (&array); } }
static dbus_bool_t find_field_for_modification (DBusHeader *header, int field, DBusTypeReader *reader, DBusTypeReader *realign_root) { dbus_bool_t retval; retval = FALSE; _dbus_type_reader_init (realign_root, header->byte_order, &_dbus_header_signature_str, FIELDS_ARRAY_SIGNATURE_OFFSET, &header->data, FIELDS_ARRAY_LENGTH_OFFSET); _dbus_type_reader_recurse (realign_root, reader); while (_dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID) { DBusTypeReader sub; unsigned char field_code; _dbus_type_reader_recurse (reader, &sub); _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_BYTE); _dbus_type_reader_read_basic (&sub, &field_code); if (field_code == (unsigned) field) { _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_STRUCT); retval = TRUE; goto done; } _dbus_type_reader_next (reader); } done: return retval; }
static void do_byteswap_test (int byte_order) { int sequence; DBusString signature; DBusString body; int opposite_order; if (!_dbus_string_init (&signature) || !_dbus_string_init (&body)) _dbus_assert_not_reached ("oom"); opposite_order = byte_order == DBUS_LITTLE_ENDIAN ? DBUS_BIG_ENDIAN : DBUS_LITTLE_ENDIAN; sequence = 0; while (dbus_internal_do_not_use_generate_bodies (sequence, byte_order, &signature, &body)) { DBusString copy; DBusTypeReader body_reader; DBusTypeReader copy_reader; if (!_dbus_string_init (©)) _dbus_assert_not_reached ("oom"); if (!_dbus_string_copy (&body, 0, ©, 0)) _dbus_assert_not_reached ("oom"); _dbus_marshal_byteswap (&signature, 0, byte_order, opposite_order, ©, 0); _dbus_type_reader_init (&body_reader, byte_order, &signature, 0, &body, 0); _dbus_type_reader_init (©_reader, opposite_order, &signature, 0, ©, 0); if (!_dbus_type_reader_equal_values (&body_reader, ©_reader)) { _dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature)); _dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body)); _dbus_verbose_bytes_of_string (©, 0, _dbus_string_get_length (©)); _dbus_warn ("Byte-swapped data did not have same values as original data"); _dbus_assert_not_reached ("test failed"); } _dbus_string_free (©); _dbus_string_set_length (&signature, 0); _dbus_string_set_length (&body, 0); ++sequence; } _dbus_string_free (&signature); _dbus_string_free (&body); printf (" %d blocks swapped from order '%c' to '%c'\n", sequence, byte_order, opposite_order); }
/** * Creates a message header from potentially-untrusted data. The * return value is #TRUE if there was enough memory and the data was * valid. If it returns #TRUE, the header will be created. If it * returns #FALSE and *validity == #DBUS_VALIDITY_UNKNOWN_OOM_ERROR, * then there wasn't enough memory. If it returns #FALSE * and *validity != #DBUS_VALIDITY_UNKNOWN_OOM_ERROR then the data was * invalid. * * The byte_order, fields_array_len, and body_len args should be from * _dbus_header_have_message_untrusted(). Validation performed in * _dbus_header_have_message_untrusted() is assumed to have been * already done. * * @param header the header (must be initialized) * @param mode whether to do validation * @param validity return location for invalidity reason * @param byte_order byte order from header * @param fields_array_len claimed length of fields array * @param body_len claimed length of body * @param header_len claimed length of header * @param str a string * @param start start of header, 8-aligned * @param len length of string to look at * @returns #FALSE if no memory or data was invalid, #TRUE otherwise */ dbus_bool_t _dbus_header_load (DBusHeader *header, DBusValidationMode mode, DBusValidity *validity, int byte_order, int fields_array_len, int header_len, int body_len, const DBusString *str, int start, int len) { int leftover; DBusValidity v; DBusTypeReader reader; DBusTypeReader array_reader; unsigned char v_byte; dbus_uint32_t v_uint32; dbus_uint32_t serial; int padding_start; int padding_len; int i; _dbus_assert (start == (int) _DBUS_ALIGN_VALUE (start, 8)); _dbus_assert (header_len <= len); _dbus_assert (_dbus_string_get_length (&header->data) == 0); if (!_dbus_string_copy_len (str, start, header_len, &header->data, 0)) { _dbus_verbose ("Failed to copy buffer into new header\n"); *validity = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; return FALSE; } if (mode == DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) { leftover = len - header_len - body_len - start; } else { v = _dbus_validate_body_with_reason (&_dbus_header_signature_str, 0, byte_order, &leftover, str, start, len); if (v != DBUS_VALID) { *validity = v; goto invalid; } } _dbus_assert (leftover < len); padding_len = header_len - (FIRST_FIELD_OFFSET + fields_array_len); padding_start = start + FIRST_FIELD_OFFSET + fields_array_len; _dbus_assert (start + header_len == (int) _DBUS_ALIGN_VALUE (padding_start, 8)); _dbus_assert (start + header_len == padding_start + padding_len); if (mode != DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) { if (!_dbus_string_validate_nul (str, padding_start, padding_len)) { *validity = DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; goto invalid; } } header->padding = padding_len; if (mode == DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) { *validity = DBUS_VALID; return TRUE; } /* We now know the data is well-formed, but we have to check that * it's valid. */ _dbus_type_reader_init (&reader, byte_order, &_dbus_header_signature_str, 0, str, start); /* BYTE ORDER */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == BYTE_ORDER_OFFSET); _dbus_type_reader_read_basic (&reader, &v_byte); _dbus_type_reader_next (&reader); _dbus_assert (v_byte == byte_order); header->byte_order = byte_order; /* MESSAGE TYPE */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == TYPE_OFFSET); _dbus_type_reader_read_basic (&reader, &v_byte); _dbus_type_reader_next (&reader); /* unknown message types are supposed to be ignored, so only validation here is * that it isn't invalid */ if (v_byte == DBUS_MESSAGE_TYPE_INVALID) { *validity = DBUS_INVALID_BAD_MESSAGE_TYPE; goto invalid; } /* FLAGS */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == FLAGS_OFFSET); _dbus_type_reader_read_basic (&reader, &v_byte); _dbus_type_reader_next (&reader); /* unknown flags should be ignored */ /* PROTOCOL VERSION */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == VERSION_OFFSET); _dbus_type_reader_read_basic (&reader, &v_byte); _dbus_type_reader_next (&reader); if (v_byte != DBUS_MAJOR_PROTOCOL_VERSION) { *validity = DBUS_INVALID_BAD_PROTOCOL_VERSION; goto invalid; } /* BODY LENGTH */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_UINT32); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == BODY_LENGTH_OFFSET); _dbus_type_reader_read_basic (&reader, &v_uint32); _dbus_type_reader_next (&reader); _dbus_assert (body_len == (signed) v_uint32); /* SERIAL */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_UINT32); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == SERIAL_OFFSET); _dbus_type_reader_read_basic (&reader, &serial); _dbus_type_reader_next (&reader); if (serial == 0) { *validity = DBUS_INVALID_BAD_SERIAL; goto invalid; } _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_ARRAY); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == FIELDS_ARRAY_LENGTH_OFFSET); _dbus_type_reader_recurse (&reader, &array_reader); while (_dbus_type_reader_get_current_type (&array_reader) != DBUS_TYPE_INVALID) { DBusTypeReader struct_reader; DBusTypeReader variant_reader; unsigned char field_code; _dbus_assert (_dbus_type_reader_get_current_type (&array_reader) == DBUS_TYPE_STRUCT); _dbus_type_reader_recurse (&array_reader, &struct_reader); _dbus_assert (_dbus_type_reader_get_current_type (&struct_reader) == DBUS_TYPE_BYTE); _dbus_type_reader_read_basic (&struct_reader, &field_code); _dbus_type_reader_next (&struct_reader); if (field_code == DBUS_HEADER_FIELD_INVALID) { _dbus_verbose ("invalid header field code\n"); *validity = DBUS_INVALID_HEADER_FIELD_CODE; goto invalid; } if (field_code > DBUS_HEADER_FIELD_LAST) { _dbus_verbose ("unknown header field code %d, skipping\n", field_code); goto next_field; } _dbus_assert (_dbus_type_reader_get_current_type (&struct_reader) == DBUS_TYPE_VARIANT); _dbus_type_reader_recurse (&struct_reader, &variant_reader); v = load_and_validate_field (header, field_code, &variant_reader); if (v != DBUS_VALID) { _dbus_verbose ("Field %d was invalid\n", field_code); *validity = v; goto invalid; } next_field: _dbus_type_reader_next (&array_reader); } /* Anything we didn't fill in is now known not to exist */ i = 0; while (i <= DBUS_HEADER_FIELD_LAST) { if (header->fields[i].value_pos == _DBUS_HEADER_FIELD_VALUE_UNKNOWN) header->fields[i].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT; ++i; } v = check_mandatory_fields (header); if (v != DBUS_VALID) { _dbus_verbose ("Mandatory fields were missing, code %d\n", v); *validity = v; goto invalid; } *validity = DBUS_VALID; return TRUE; invalid: _dbus_string_set_length (&header->data, 0); return FALSE; }