/** * See dbus_message_get_serial() * * @param header the header * @returns the client serial */ dbus_uint32_t _dbus_header_get_serial (DBusHeader *header) { return _dbus_marshal_read_uint32 (&header->data, SERIAL_OFFSET, header->byte_order, NULL); }
static dbus_bool_t generate_wrong_length (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int lengths[] = { -42, -17, -16, -15, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 30 }; int adjust; int len_seq; restart: len_seq = iter_get_sequence (iter); if (len_seq == _DBUS_N_ELEMENTS (lengths)) return FALSE; _dbus_assert (len_seq < _DBUS_N_ELEMENTS (lengths)); iter_recurse (iter); if (!generate_many_bodies (iter, data, expected_validity)) { iter_set_sequence (iter, 0); /* reset to first body */ iter_unrecurse (iter); iter_next (iter); /* next length adjustment */ goto restart; } iter_unrecurse (iter); adjust = lengths[len_seq]; if (adjust < 0) { if ((_dbus_string_get_length (data) + adjust) < DBUS_MINIMUM_HEADER_SIZE) _dbus_string_set_length (data, DBUS_MINIMUM_HEADER_SIZE); else _dbus_string_shorten (data, - adjust); *expected_validity = DBUS_INVALID_FOR_UNKNOWN_REASON; } else { if (!_dbus_string_lengthen (data, adjust)) _dbus_assert_not_reached ("oom"); *expected_validity = DBUS_INVALID_TOO_MUCH_DATA; } /* Fixup lengths */ { int old_body_len; int new_body_len; int byte_order; _dbus_assert (_dbus_string_get_length (data) >= DBUS_MINIMUM_HEADER_SIZE); byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET); old_body_len = _dbus_marshal_read_uint32 (data, BODY_LENGTH_OFFSET, byte_order, NULL); _dbus_assert (old_body_len < _dbus_string_get_length (data)); new_body_len = old_body_len + adjust; if (new_body_len < 0) { new_body_len = 0; /* we just munged the header, and aren't sure how */ *expected_validity = DBUS_VALIDITY_UNKNOWN; } _dbus_verbose ("changing body len from %u to %u by adjust %d\n", old_body_len, new_body_len, adjust); _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET, new_body_len, byte_order); } return TRUE; }
static dbus_bool_t generate_uint32_changed (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int body_seq; int byte_seq; int change_seq; dbus_uint32_t v_UINT32; int byte_order; const UIntChange *change; int base_depth; /* Outer loop is each body, next loop is each change, * inner loop is each change location */ base_depth = iter->depth; next_body: _dbus_assert (iter->depth == (base_depth + 0)); _dbus_string_set_length (data, 0); body_seq = iter_get_sequence (iter); if (!generate_many_bodies (iter, data, expected_validity)) return FALSE; _dbus_assert (iter->depth == (base_depth + 0)); iter_set_sequence (iter, body_seq); /* undo the "next" from generate_many_bodies */ iter_recurse (iter); next_change: _dbus_assert (iter->depth == (base_depth + 1)); change_seq = iter_get_sequence (iter); if (change_seq == _DBUS_N_ELEMENTS (uint32_changes)) { /* Reset change count */ iter_set_sequence (iter, 0); iter_unrecurse (iter); iter_next (iter); goto next_body; } _dbus_assert (iter->depth == (base_depth + 1)); iter_recurse (iter); _dbus_assert (iter->depth == (base_depth + 2)); byte_seq = iter_get_sequence (iter); /* skip 4 bytes at a time */ iter_next (iter); iter_next (iter); iter_next (iter); iter_next (iter); iter_unrecurse (iter); _dbus_assert (_DBUS_ALIGN_VALUE (byte_seq, 4) == (unsigned) byte_seq); if (byte_seq >= (_dbus_string_get_length (data) - 4)) { /* reset byte count */ _dbus_assert (iter->depth == (base_depth + 1)); iter_recurse (iter); _dbus_assert (iter->depth == (base_depth + 2)); iter_set_sequence (iter, 0); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 1)); iter_next (iter); goto next_change; } _dbus_assert (byte_seq <= (_dbus_string_get_length (data) - 4)); byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET); v_UINT32 = _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL); change = &uint32_changes[change_seq]; if (change->type == CHANGE_TYPE_ADJUST) { v_UINT32 += (int) change->value; } else { v_UINT32 = change->value; } #if 0 printf ("body %d change %d pos %d ", body_seq, change_seq, byte_seq); if (change->type == CHANGE_TYPE_ADJUST) printf ("adjust by %d", (int) change->value); else printf ("set to %u", change->value); printf (" \t%u -> %u\n", _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL), v_UINT32); #endif _dbus_marshal_set_uint32 (data, byte_seq, v_UINT32, byte_order); *expected_validity = DBUS_VALIDITY_UNKNOWN; _dbus_assert (iter->depth == (base_depth + 1)); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 0)); return TRUE; }
static DBusValidity load_and_validate_field (DBusHeader *header, int field, DBusTypeReader *variant_reader) { int type; int expected_type; const DBusString *value_str; int value_pos; int str_data_pos; dbus_uint32_t v_UINT32; int bad_string_code; dbus_bool_t (* string_validation_func) (const DBusString *str, int start, int len); /* Supposed to have been checked already */ _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); _dbus_assert (field != DBUS_HEADER_FIELD_INVALID); /* Before we can cache a field, we need to know it has the right type */ type = _dbus_type_reader_get_current_type (variant_reader); _dbus_assert (_dbus_header_field_types[field].code == field); expected_type = EXPECTED_TYPE_OF_FIELD (field); if (type != expected_type) { _dbus_verbose ("Field %d should have type %d but has %d\n", field, expected_type, type); return DBUS_INVALID_HEADER_FIELD_HAS_WRONG_TYPE; } /* If the field was provided twice, we aren't happy */ if (header->fields[field].value_pos >= 0) { _dbus_verbose ("Header field %d seen a second time\n", field); return DBUS_INVALID_HEADER_FIELD_APPEARS_TWICE; } /* Now we can cache and look at the field content */ _dbus_verbose ("initially caching field %d\n", field); _dbus_header_cache_one (header, field, variant_reader); string_validation_func = NULL; /* make compiler happy that all this is initialized */ v_UINT32 = 0; value_str = NULL; value_pos = -1; str_data_pos = -1; bad_string_code = DBUS_VALID; if (expected_type == DBUS_TYPE_UINT32) { _dbus_header_get_field_basic (header, field, expected_type, &v_UINT32); } else if (expected_type == DBUS_TYPE_STRING || expected_type == DBUS_TYPE_OBJECT_PATH || expected_type == DBUS_TYPE_SIGNATURE) { _dbus_header_get_field_raw (header, field, &value_str, &value_pos); str_data_pos = _DBUS_ALIGN_VALUE (value_pos, 4) + 4; } else { _dbus_assert_not_reached ("none of the known fields should have this type"); } switch (field) { case DBUS_HEADER_FIELD_DESTINATION: string_validation_func = _dbus_validate_bus_name; bad_string_code = DBUS_INVALID_BAD_DESTINATION; break; case DBUS_HEADER_FIELD_INTERFACE: string_validation_func = _dbus_validate_interface; bad_string_code = DBUS_INVALID_BAD_INTERFACE; if (_dbus_string_equal_substring (&_dbus_local_interface_str, 0, _dbus_string_get_length (&_dbus_local_interface_str), value_str, str_data_pos)) { _dbus_verbose ("Message is on the local interface\n"); return DBUS_INVALID_USES_LOCAL_INTERFACE; } break; case DBUS_HEADER_FIELD_MEMBER: string_validation_func = _dbus_validate_member; bad_string_code = DBUS_INVALID_BAD_MEMBER; break; case DBUS_HEADER_FIELD_ERROR_NAME: string_validation_func = _dbus_validate_error_name; bad_string_code = DBUS_INVALID_BAD_ERROR_NAME; break; case DBUS_HEADER_FIELD_SENDER: string_validation_func = _dbus_validate_bus_name; bad_string_code = DBUS_INVALID_BAD_SENDER; break; case DBUS_HEADER_FIELD_PATH: /* OBJECT_PATH was validated generically due to its type */ string_validation_func = NULL; if (_dbus_string_equal_substring (&_dbus_local_path_str, 0, _dbus_string_get_length (&_dbus_local_path_str), value_str, str_data_pos)) { _dbus_verbose ("Message is from the local path\n"); return DBUS_INVALID_USES_LOCAL_PATH; } break; case DBUS_HEADER_FIELD_REPLY_SERIAL: /* Can't be 0 */ if (v_UINT32 == 0) { return DBUS_INVALID_BAD_SERIAL; } break; case DBUS_HEADER_FIELD_SIGNATURE: /* SIGNATURE validated generically due to its type */ string_validation_func = NULL; break; default: _dbus_assert_not_reached ("unknown field shouldn't be seen here"); break; } if (string_validation_func) { dbus_uint32_t len; _dbus_assert (bad_string_code != DBUS_VALID); len = _dbus_marshal_read_uint32 (value_str, value_pos, header->byte_order, NULL); #if 0 _dbus_verbose ("Validating string header field; code %d if fails\n", bad_string_code); #endif if (!(*string_validation_func) (value_str, str_data_pos, len)) return bad_string_code; } return DBUS_VALID; }
/** * Given data long enough to contain the length of the message body * and the fields array, check whether the data is long enough to * contain the entire message (assuming the claimed lengths are * accurate). Also checks that the lengths are in sanity parameters. * * @param max_message_length maximum length of a valid message * @param validity return location for why the data is invalid if it is * @param byte_order return location for byte order * @param fields_array_len return location for claimed fields array length * @param header_len return location for claimed header length * @param body_len return location for claimed body length * @param str the data * @param start start of data, 8-aligned * @param len length of data * @returns #TRUE if the data is long enough for the claimed length, and the lengths were valid */ dbus_bool_t _dbus_header_have_message_untrusted (int max_message_length, DBusValidity *validity, int *byte_order, int *fields_array_len, int *header_len, int *body_len, const DBusString *str, int start, int len) { dbus_uint32_t header_len_unsigned; dbus_uint32_t fields_array_len_unsigned; dbus_uint32_t body_len_unsigned; _dbus_assert (start >= 0); _dbus_assert (start < _DBUS_INT32_MAX / 2); _dbus_assert (len >= 0); _dbus_assert (start == (int) _DBUS_ALIGN_VALUE (start, 8)); *byte_order = _dbus_string_get_byte (str, start + BYTE_ORDER_OFFSET); if (*byte_order != DBUS_LITTLE_ENDIAN && *byte_order != DBUS_BIG_ENDIAN) { *validity = DBUS_INVALID_BAD_BYTE_ORDER; return FALSE; } _dbus_assert (FIELDS_ARRAY_LENGTH_OFFSET + 4 <= len); fields_array_len_unsigned = _dbus_marshal_read_uint32 (str, start + FIELDS_ARRAY_LENGTH_OFFSET, *byte_order, NULL); if (fields_array_len_unsigned > (unsigned) max_message_length) { *validity = DBUS_INVALID_INSANE_FIELDS_ARRAY_LENGTH; return FALSE; } _dbus_assert (BODY_LENGTH_OFFSET + 4 < len); body_len_unsigned = _dbus_marshal_read_uint32 (str, start + BODY_LENGTH_OFFSET, *byte_order, NULL); if (body_len_unsigned > (unsigned) max_message_length) { *validity = DBUS_INVALID_INSANE_BODY_LENGTH; return FALSE; } header_len_unsigned = FIRST_FIELD_OFFSET + fields_array_len_unsigned; header_len_unsigned = _DBUS_ALIGN_VALUE (header_len_unsigned, 8); /* overflow should be impossible since the lengths aren't allowed to * be huge. */ _dbus_assert (max_message_length < _DBUS_INT32_MAX / 2); if (body_len_unsigned + header_len_unsigned > (unsigned) max_message_length) { *validity = DBUS_INVALID_MESSAGE_TOO_LONG; return FALSE; } _dbus_assert (body_len_unsigned < (unsigned) _DBUS_INT32_MAX); _dbus_assert (fields_array_len_unsigned < (unsigned) _DBUS_INT32_MAX); _dbus_assert (header_len_unsigned < (unsigned) _DBUS_INT32_MAX); *body_len = body_len_unsigned; *fields_array_len = fields_array_len_unsigned; *header_len = header_len_unsigned; *validity = DBUS_VALID; _dbus_verbose ("have %d bytes, need body %u + header %u = %u\n", len, body_len_unsigned, header_len_unsigned, body_len_unsigned + header_len_unsigned); return (body_len_unsigned + header_len_unsigned) <= (unsigned) len; }