From b3a3969897930eeda308113acbbb3f98069ee1ab Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Tue, 22 Apr 2003 19:34:33 +0000 Subject: 2003-04-22 Havoc Pennington * test/data/valid-messages/opposite-endian.message: fix test to use proper type for rply field * test/data/invalid-messages: add tests for below validation * dbus/dbus-message.c (decode_header_data): validate field types, and validate that named fields are valid names (decode_name_field): consider messages in the org.freedesktop.Local. namespace to be invalid. * dbus/dbus-string.c (_dbus_string_validate_name): new --- dbus/dbus-connection.c | 2 +- dbus/dbus-message.c | 186 +++++++++++++++++++++++++++++++------------------ dbus/dbus-protocol.h | 12 +++- dbus/dbus-string.c | 120 +++++++++++++++++++++++++++++++ dbus/dbus-string.h | 6 ++ 5 files changed, 257 insertions(+), 69 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 7a89da3e..eb331662 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -267,7 +267,7 @@ _dbus_connection_queue_received_message_link (DBusConnection *connection, _dbus_list_append_link (&connection->incoming_messages, link); message = link->data; - + /* If this is a reply we're waiting on, remove timeout for it */ reply_serial = dbus_message_get_reply_serial (message); if (reply_serial != -1) diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index ee42947d..af949fb4 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -2910,8 +2910,9 @@ append_array_type (DBusMessageRealIter *real, existing_element_type = iter_get_array_type (real, array_type_pos); if (existing_element_type != element_type) { - _dbus_warn ("Appending array of %d, when expecting array of %d\n", - element_type, existing_element_type); + _dbus_warn ("Appending array of %s, when expecting array of %s\n", + _dbus_type_to_string (element_type), + _dbus_type_to_string (existing_element_type)); _dbus_string_set_length (&real->message->body, real->pos); return FALSE; } @@ -3627,7 +3628,76 @@ _dbus_message_loader_get_buffer (DBusMessageLoader *loader, #define DBUS_HEADER_FIELD_SENDER_AS_UINT32 \ FOUR_CHARS_TO_UINT32 ('s', 'n', 'd', 'r') -/* FIXME impose max length on name, srvc, sndr */ +static dbus_bool_t +decode_string_field (const DBusString *data, + HeaderField fields[FIELD_LAST], + int pos, + int type, + int field, + const char *field_name) +{ + DBusString tmp; + int string_data_pos; + + if (fields[field].offset >= 0) + { + _dbus_verbose ("%s field provided twice\n", + field_name); + return FALSE; + } + + if (type != DBUS_TYPE_STRING) + { + _dbus_verbose ("%s field has wrong type\n", field_name); + return FALSE; + } + + /* skip padding after typecode, skip string length; + * we assume that the string arg has already been validated + * for sanity and UTF-8 + */ + string_data_pos = _DBUS_ALIGN_VALUE (pos, 4) + 4; + _dbus_assert (string_data_pos < _dbus_string_get_length (data)); + + _dbus_string_init_const (&tmp, + _dbus_string_get_const_data (data) + string_data_pos); + + if (field == FIELD_NAME) + { + if (!_dbus_string_validate_name (&tmp, 0, _dbus_string_get_length (&tmp))) + { + _dbus_verbose ("%s field has invalid content \"%s\"\n", + field_name, _dbus_string_get_const_data (&tmp)); + return FALSE; + } + + if (_dbus_string_starts_with_c_str (&tmp, + DBUS_NAMESPACE_LOCAL_MESSAGE)) + { + _dbus_verbose ("Message is in the local namespace\n"); + return FALSE; + } + } + else + { + if (!_dbus_string_validate_service (&tmp, 0, _dbus_string_get_length (&tmp))) + { + _dbus_verbose ("%s field has invalid content \"%s\"\n", + field_name, _dbus_string_get_const_data (&tmp)); + return FALSE; + } + } + + fields[field].offset = _DBUS_ALIGN_VALUE (pos, 4); + +#if 0 + _dbus_verbose ("Found field %s name at offset %d\n", + field_name, fields[field].offset); +#endif + + return TRUE; +} + static dbus_bool_t decode_header_data (const DBusString *data, int header_len, @@ -3672,51 +3742,46 @@ decode_header_data (const DBusString *data, pos += 4; _dbus_assert (_DBUS_ALIGN_ADDRESS (field, 4) == field); + + if (!_dbus_marshal_validate_type (data, pos, &type, &pos)) + { + _dbus_verbose ("Failed to validate type of named header field\n"); + return FALSE; + } + + if (!_dbus_marshal_validate_arg (data, byte_order, 0, type, -1, pos, &new_pos)) + { + _dbus_verbose ("Failed to validate argument to named header field\n"); + return FALSE; + } + if (new_pos > header_len) + { + _dbus_verbose ("Named header field tries to extend beyond header length\n"); + return FALSE; + } + switch (DBUS_UINT32_FROM_BE (*(int*)field)) { case DBUS_HEADER_FIELD_SERVICE_AS_UINT32: - if (fields[FIELD_SERVICE].offset >= 0) - { - _dbus_verbose ("%s field provided twice\n", - DBUS_HEADER_FIELD_SERVICE); - return FALSE; - } - - fields[FIELD_SERVICE].offset = _DBUS_ALIGN_VALUE (pos + 1, 4); -#if 0 - _dbus_verbose ("Found service name at offset %d\n", - fields[FIELD_SERVICE].offset); -#endif + if (!decode_string_field (data, fields, pos, type, + FIELD_SERVICE, + DBUS_HEADER_FIELD_SERVICE)) + return FALSE; break; case DBUS_HEADER_FIELD_NAME_AS_UINT32: - if (fields[FIELD_NAME].offset >= 0) - { - _dbus_verbose ("%s field provided twice\n", - DBUS_HEADER_FIELD_NAME); - return FALSE; - } - - fields[FIELD_NAME].offset = _DBUS_ALIGN_VALUE (pos + 1, 4); - -#if 0 - _dbus_verbose ("Found message name at offset %d\n", - fields[FIELD_NAME].offset); -#endif + if (!decode_string_field (data, fields, pos, type, + FIELD_NAME, + DBUS_HEADER_FIELD_NAME)) + return FALSE; break; - case DBUS_HEADER_FIELD_SENDER_AS_UINT32: - if (fields[FIELD_SENDER].offset >= 0) - { - _dbus_verbose ("%s field provided twice\n", - DBUS_HEADER_FIELD_SENDER); - return FALSE; - } - - fields[FIELD_SENDER].offset = _DBUS_ALIGN_VALUE (pos + 1, 4); - _dbus_verbose ("Found sender name at offset %d\n", - fields[FIELD_NAME].offset); + case DBUS_HEADER_FIELD_SENDER_AS_UINT32: + if (!decode_string_field (data, fields, pos, type, + FIELD_SENDER, + DBUS_HEADER_FIELD_SENDER)) + return FALSE; break; case DBUS_HEADER_FIELD_REPLY_AS_UINT32: @@ -3726,8 +3791,14 @@ decode_header_data (const DBusString *data, DBUS_HEADER_FIELD_REPLY); return FALSE; } + + if (type != DBUS_TYPE_UINT32) + { + _dbus_verbose ("%s field has wrong type\n", DBUS_HEADER_FIELD_REPLY); + return FALSE; + } - fields[FIELD_REPLY_SERIAL].offset = _DBUS_ALIGN_VALUE (pos + 1, 4); + fields[FIELD_REPLY_SERIAL].offset = _DBUS_ALIGN_VALUE (pos, 4); _dbus_verbose ("Found reply serial at offset %d\n", fields[FIELD_REPLY_SERIAL].offset); @@ -3737,24 +3808,6 @@ decode_header_data (const DBusString *data, _dbus_verbose ("Ignoring an unknown header field: %c%c%c%c at offset %d\n", field[0], field[1], field[2], field[3], pos); } - - if (!_dbus_marshal_validate_type (data, pos, &type, &pos)) - { - _dbus_verbose ("Failed to validate type of named header field\n"); - return FALSE; - } - - if (!_dbus_marshal_validate_arg (data, byte_order, 0, type, -1, pos, &new_pos)) - { - _dbus_verbose ("Failed to validate argument to named header field\n"); - return FALSE; - } - - if (new_pos > header_len) - { - _dbus_verbose ("Named header field tries to extend beyond header length\n"); - return FALSE; - } pos = new_pos; } @@ -3772,12 +3825,13 @@ decode_header_data (const DBusString *data, } } - if (fields[FIELD_NAME].offset < 0) - { - _dbus_verbose ("No %s field provided\n", - DBUS_HEADER_FIELD_NAME); - return FALSE; - } + /* Name field is mandatory */ + if (fields[FIELD_NAME].offset < 0) + { + _dbus_verbose ("No %s field provided\n", + DBUS_HEADER_FIELD_NAME); + return FALSE; + } if (message_padding) *message_padding = header_len - pos; @@ -5076,7 +5130,7 @@ _dbus_message_test (const char *test_data_dir) _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter)); /* Test the vararg functions */ - message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage"); + message = dbus_message_new ("org.freedesktop.DBus.Test", "test.Message"); _dbus_message_set_serial (message, 1); dbus_message_append_args (message, DBUS_TYPE_INT32, -0x12345678, @@ -5121,7 +5175,7 @@ _dbus_message_test (const char *test_data_dir) dbus_message_unref (message); dbus_message_unref (copy); - message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage"); + message = dbus_message_new ("org.freedesktop.DBus.Test", "test.Message"); _dbus_message_set_serial (message, 1); dbus_message_set_reply_serial (message, 0x12345678); diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index 651969c4..314a9934 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -53,7 +53,10 @@ extern "C" { #define DBUS_TYPE_DICT 10 #define DBUS_TYPE_LAST DBUS_TYPE_DICT - + +/* Max length in bytes of a service or message name */ +#define DBUS_MAXIMUM_NAME_LENGTH 256 + /* Header flags */ #define DBUS_HEADER_FLAG_ERROR 0x1 @@ -92,7 +95,12 @@ extern "C" { #define DBUS_MESSAGE_SERVICE_DELETED "org.freedesktop.DBus.ServiceDeleted" #define DBUS_MESSAGE_SERVICE_LOST "org.freedesktop.DBus.ServiceLost" -#define DBUS_MESSAGE_LOCAL_DISCONNECT "org.freedesktop.Local.Disconnect" + +/* This namespace is reserved for locally-synthesized messages, you can't + * send messages that have this namespace. + */ +#define DBUS_NAMESPACE_LOCAL_MESSAGE "org.freedesktop.Local." +#define DBUS_MESSAGE_LOCAL_DISCONNECT DBUS_NAMESPACE_LOCAL_MESSAGE"Disconnect" #ifdef __cplusplus } diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index 71fc5fcc..8abc74ac 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -28,6 +28,7 @@ #include "dbus-marshal.h" #define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1 #include "dbus-string-private.h" +#include "dbus-protocol.h" /** * @defgroup DBusString string class @@ -2641,6 +2642,125 @@ _dbus_string_validate_nul (const DBusString *str, return TRUE; } +/** + * Checks that the given range of the string is a valid message name + * in the D-BUS protocol. This includes a length restriction, etc., + * see the specification. It does not validate UTF-8, that has to be + * done separately for now. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that isn't in the string. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_string_validate_name (const DBusString *str, + int start, + int len) +{ + const unsigned char *s; + const unsigned char *end; + dbus_bool_t saw_dot; + + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (start >= 0); + _dbus_assert (len >= 0); + _dbus_assert (start <= real->len); + + if (len > real->len - start) + return FALSE; + + if (len > DBUS_MAXIMUM_NAME_LENGTH) + return FALSE; + + if (len == 0) + return FALSE; + + saw_dot = FALSE; + s = real->str + start; + end = s + len; + while (s != end) + { + if (*s == '.') + { + saw_dot = TRUE; + break; + } + + ++s; + } + + if (!saw_dot) + return FALSE; + + return TRUE; +} + + +/** + * Checks that the given range of the string is a valid service name + * in the D-BUS protocol. This includes a length restriction, etc., + * see the specification. It does not validate UTF-8, that has to be + * done separately for now. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that isn't in the string. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_string_validate_service (const DBusString *str, + int start, + int len) +{ + const unsigned char *s; + const unsigned char *end; + dbus_bool_t saw_dot; + dbus_bool_t is_base_service; + + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (start >= 0); + _dbus_assert (len >= 0); + _dbus_assert (start <= real->len); + + if (len > real->len - start) + return FALSE; + + if (len > DBUS_MAXIMUM_NAME_LENGTH) + return FALSE; + + if (len == 0) + return FALSE; + + is_base_service = _dbus_string_get_byte (str, start) == ':'; + if (is_base_service) + return TRUE; /* can have any content */ + + /* non-base-service must have the '.' indicating a namespace */ + + saw_dot = FALSE; + s = real->str + start; + end = s + len; + while (s != end) + { + if (*s == '.') + { + saw_dot = TRUE; + break; + } + + ++s; + } + + return saw_dot; +} + /** * Clears all allocated bytes in the string to zero. * diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h index 065c9caa..b9b298ae 100644 --- a/dbus/dbus-string.h +++ b/dbus/dbus-string.h @@ -210,6 +210,12 @@ dbus_bool_t _dbus_string_validate_utf8 (const DBusString *str, dbus_bool_t _dbus_string_validate_nul (const DBusString *str, int start, int len); +dbus_bool_t _dbus_string_validate_name (const DBusString *str, + int start, + int len); +dbus_bool_t _dbus_string_validate_service (const DBusString *str, + int start, + int len); void _dbus_string_zero (DBusString *str); -- cgit