2003-01-30 Havoc Pennington <hp@pobox.com>

* dbus/dbus-message.c: use message->byte_order instead of
	DBUS_COMPILER_BYTE_ORDER throughout.
	(dbus_message_create_header): pad header to align the
	start of the body of the message to 8-byte boundary

	* dbus/dbus-marshal.h: make all the demarshalers take const
	DBusString arguments.

	* dbus/dbus-message.c (_dbus_message_loader_return_buffer):
	validate message args here, so we don't have to do slow validation
	later, and so we catch bad messages as they are incoming. Also add
	better checks on header_len and body_len. Also fill in
	message->byte_order

	* dbus/dbus-string.c (_dbus_string_validate_utf8): new (not
	implemented properly)
	(_dbus_string_validate_nul): new function to check all-nul

	* dbus/dbus-marshal.c (_dbus_marshal_get_field_end_pos): rename
	get_arg_end_pos and remove all validation
	(_dbus_marshal_validate_arg): actually do validation here.
This commit is contained in:
Havoc Pennington 2003-01-30 04:20:44 +00:00
parent 8fdd8915bd
commit 7ba714ad7f
9 changed files with 613 additions and 142 deletions

View file

@ -1,3 +1,27 @@
2003-01-30 Havoc Pennington <hp@pobox.com>
* dbus/dbus-message.c: use message->byte_order instead of
DBUS_COMPILER_BYTE_ORDER throughout.
(dbus_message_create_header): pad header to align the
start of the body of the message to 8-byte boundary
* dbus/dbus-marshal.h: make all the demarshalers take const
DBusString arguments.
* dbus/dbus-message.c (_dbus_message_loader_return_buffer):
validate message args here, so we don't have to do slow validation
later, and so we catch bad messages as they are incoming. Also add
better checks on header_len and body_len. Also fill in
message->byte_order
* dbus/dbus-string.c (_dbus_string_validate_utf8): new (not
implemented properly)
(_dbus_string_validate_nul): new function to check all-nul
* dbus/dbus-marshal.c (_dbus_marshal_get_field_end_pos): rename
get_arg_end_pos and remove all validation
(_dbus_marshal_validate_arg): actually do validation here.
2003-01-29 Havoc Pennington <hp@pobox.com>
* dbus/dbus-message.c (check_message_handling): fix assertion

View file

@ -73,7 +73,7 @@ _dbus_unpack_uint32 (int byte_order,
return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data);
else
return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data);
}
}
/**
* Unpacks a 32 bit signed integer from a data pointer
@ -504,7 +504,7 @@ _dbus_marshal_string_array (DBusString *str,
* @returns the demarshaled double.
*/
double
_dbus_demarshal_double (DBusString *str,
_dbus_demarshal_double (const DBusString *str,
int byte_order,
int pos,
int *new_pos)
@ -537,7 +537,7 @@ _dbus_demarshal_double (DBusString *str,
* @returns the demarshaled integer.
*/
dbus_int32_t
_dbus_demarshal_int32 (DBusString *str,
_dbus_demarshal_int32 (const DBusString *str,
int byte_order,
int pos,
int *new_pos)
@ -564,7 +564,7 @@ _dbus_demarshal_int32 (DBusString *str,
* @returns the demarshaled integer.
*/
dbus_uint32_t
_dbus_demarshal_uint32 (DBusString *str,
_dbus_demarshal_uint32 (const DBusString *str,
int byte_order,
int pos,
int *new_pos)
@ -598,7 +598,7 @@ _dbus_demarshal_uint32 (DBusString *str,
* @returns the demarshaled string.
*/
char *
_dbus_demarshal_string (DBusString *str,
_dbus_demarshal_string (const DBusString *str,
int byte_order,
int pos,
int *new_pos)
@ -606,7 +606,7 @@ _dbus_demarshal_string (DBusString *str,
int len;
char *retval;
const char *data;
len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
retval = dbus_malloc (len + 1);
@ -641,7 +641,7 @@ _dbus_demarshal_string (DBusString *str,
* @returns the demarshaled data.
*/
unsigned char *
_dbus_demarshal_byte_array (DBusString *str,
_dbus_demarshal_byte_array (const DBusString *str,
int byte_order,
int pos,
int *new_pos,
@ -685,7 +685,7 @@ _dbus_demarshal_byte_array (DBusString *str,
* @returns the demarshaled data.
*/
dbus_int32_t *
_dbus_demarshal_int32_array (DBusString *str,
_dbus_demarshal_int32_array (const DBusString *str,
int byte_order,
int pos,
int *new_pos,
@ -724,7 +724,7 @@ _dbus_demarshal_int32_array (DBusString *str,
* @returns the demarshaled data.
*/
dbus_uint32_t *
_dbus_demarshal_uint32_array (DBusString *str,
_dbus_demarshal_uint32_array (const DBusString *str,
int byte_order,
int pos,
int *new_pos,
@ -763,7 +763,7 @@ _dbus_demarshal_uint32_array (DBusString *str,
* @returns the demarshaled data.
*/
double *
_dbus_demarshal_double_array (DBusString *str,
_dbus_demarshal_double_array (const DBusString *str,
int byte_order,
int pos,
int *new_pos,
@ -802,7 +802,7 @@ _dbus_demarshal_double_array (DBusString *str,
* @returns the demarshaled data.
*/
char **
_dbus_demarshal_string_array (DBusString *str,
_dbus_demarshal_string_array (const DBusString *str,
int byte_order,
int pos,
int *new_pos,
@ -843,32 +843,24 @@ _dbus_demarshal_string_array (DBusString *str,
}
/**
* Returns the position right after the end position
* end position of a field. Validates the field
* contents as required (e.g. ensures that
* string fields have a valid length and
* are nul-terminated).
* Returns the position right after the end of an argument. PERFORMS
* NO VALIDATION WHATSOEVER. The message must have been previously
* validated.
*
* @todo security: audit the field validation code.
*
* @todo warns on invalid type in a message, but
* probably the whole message needs to be dumped,
* or we might even drop the connection due
* to bad protocol. Needs better error handling.
* Possible security issue.
* @todo handle DBUS_TYPE_NIL
*
* @param str a string
* @param byte_order the byte order to use
* @param pos the pos where the field starts
* @param pos the pos where the arg starts
* @param end_pos pointer where the position right
* after the end position will follow
* @returns TRUE if more data exists after the field
* @returns TRUE if more data exists after the arg
*/
dbus_bool_t
_dbus_marshal_get_field_end_pos (DBusString *str,
int byte_order,
int pos,
int *end_pos)
_dbus_marshal_get_arg_end_pos (const DBusString *str,
int byte_order,
int pos,
int *end_pos)
{
const char *data;
@ -906,21 +898,8 @@ _dbus_marshal_get_field_end_pos (DBusString *str,
len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &pos);
*end_pos = pos + len + 1;
if (*end_pos > _dbus_string_get_length (str))
{
_dbus_verbose ("string length outside length of the message\n");
return FALSE;
}
if (_dbus_string_get_byte (str, pos+len) != '\0')
{
_dbus_verbose ("string field not nul-terminated\n");
return FALSE;
}
break;
}
break;
case DBUS_TYPE_BYTE_ARRAY:
{
@ -930,9 +909,8 @@ _dbus_marshal_get_field_end_pos (DBusString *str,
len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &pos);
*end_pos = pos + len;
break;
}
break;
case DBUS_TYPE_INT32_ARRAY:
{
@ -943,9 +921,8 @@ _dbus_marshal_get_field_end_pos (DBusString *str,
*end_pos = _DBUS_ALIGN_VALUE (new_pos, sizeof (dbus_int32_t))
+ (len * sizeof (dbus_int32_t));
break;
}
break;
case DBUS_TYPE_UINT32_ARRAY:
{
@ -956,9 +933,8 @@ _dbus_marshal_get_field_end_pos (DBusString *str,
*end_pos = _DBUS_ALIGN_VALUE (new_pos, sizeof (dbus_uint32_t))
+ (len * sizeof (dbus_uint32_t));
break;
}
break;
case DBUS_TYPE_DOUBLE_ARRAY:
{
@ -969,9 +945,8 @@ _dbus_marshal_get_field_end_pos (DBusString *str,
*end_pos = _DBUS_ALIGN_VALUE (new_pos, sizeof (double))
+ (len * sizeof (double));
break;
}
break;
case DBUS_TYPE_STRING_ARRAY:
{
@ -990,10 +965,12 @@ _dbus_marshal_get_field_end_pos (DBusString *str,
}
*end_pos = pos;
break;
}
}
break;
default:
_dbus_warn ("Unknown message field type %d\n", *data);
_dbus_warn ("Unknown message arg type %d\n", *data);
_dbus_assert_not_reached ("Unknown message argument type\n");
return FALSE;
}
@ -1003,6 +980,257 @@ _dbus_marshal_get_field_end_pos (DBusString *str,
return TRUE;
}
/**
* Demarshals and validates a length; returns < 0 if the validation
* fails. The length is required to be small enough that
* len*sizeof(double) will not overflow, and small enough to fit in a
* signed integer.
*
* @param str the string
* @param byte_order the byte order
* @param pos the unaligned string position (snap to next aligned)
*/
static int
demarshal_and_validate_len (const DBusString *str,
int byte_order,
int pos,
int *new_pos)
{
int align_4 = _DBUS_ALIGN_VALUE (pos, 4);
unsigned int len;
if ((align_4 + 4) >= _dbus_string_get_length (str))
{
_dbus_verbose ("not enough room in message for array length\n");
return -1;
}
if (!_dbus_string_validate_nul (str, pos,
align_4 - pos))
{
_dbus_verbose ("array length alignment padding not initialized to nul\n");
return -1;
}
len = _dbus_demarshal_uint32 (str, byte_order, align_4, new_pos);
/* note that the len may be a number of doubles, so we need it to be
* at least SIZE_T_MAX / 8, but make it smaller just to keep things
* sane. We end up using ints for most sizes to avoid unsigned mess
* so limit to maximum 32-bit signed int divided by at least 8, more
* for a bit of paranoia margin. INT_MAX/32 is about 65 megabytes.
*/
#define MAX_ARRAY_LENGTH (((unsigned int)_DBUS_INT_MAX) / 32)
if (len > MAX_ARRAY_LENGTH)
{
_dbus_verbose ("array length %u exceeds maximum of %u\n",
len, MAX_ARRAY_LENGTH);
return -1;
}
else
return (int) len;
}
static dbus_bool_t
validate_string (const DBusString *str,
int pos,
int len_without_nul,
int *end_pos)
{
*end_pos = pos + len_without_nul + 1;
if (*end_pos > _dbus_string_get_length (str))
{
_dbus_verbose ("string length outside length of the message\n");
return FALSE;
}
if (_dbus_string_get_byte (str, pos + len_without_nul) != '\0')
{
_dbus_verbose ("string arg not nul-terminated\n");
return FALSE;
}
if (!_dbus_string_validate_utf8 (str, pos, len_without_nul))
{
_dbus_verbose ("string is not valid UTF-8\n");
return FALSE;
}
return TRUE;
}
/**
* Validates an argument, checking that it is well-formed, for example
* no ludicrous length fields, strings are nul-terminated, etc.
* Returns the end position of the argument in end_pos, and
* returns #TRUE if a valid arg begins at "pos"
*
* @todo security: need to audit this function.
*
* @todo handle DBUS_TYPE_NIL
*
* @param str a string
* @param byte_order the byte order to use
* @param pos the pos where the arg starts (offset of its typecode)
* @param end_pos pointer where the position right
* after the end position will follow
* @returns #TRUE if the arg is valid.
*/
dbus_bool_t
_dbus_marshal_validate_arg (const DBusString *str,
int byte_order,
int pos,
int *end_pos)
{
const char *data;
if (pos >= _dbus_string_get_length (str))
return FALSE;
_dbus_string_get_const_data_len (str, &data, pos, 1);
switch (*data)
{
case DBUS_TYPE_INVALID:
return FALSE;
break;
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
{
int align_4 = _DBUS_ALIGN_VALUE (pos + 1, 4);
if (!_dbus_string_validate_nul (str, pos + 1,
align_4 - pos - 1))
{
_dbus_verbose ("int32/uint32 alignment padding not initialized to nul\n");
return FALSE;
}
*end_pos = align_4 + 4;
}
break;
case DBUS_TYPE_DOUBLE:
{
int align_8 = _DBUS_ALIGN_VALUE (pos + 1, 8);
_dbus_verbose_bytes_of_string (str, pos, (align_8 + 8 - pos));
if (!_dbus_string_validate_nul (str, pos + 1,
align_8 - pos - 1))
{
_dbus_verbose ("double alignment padding not initialized to nul\n");
return FALSE;
}
*end_pos = align_8 + 8;
}
break;
case DBUS_TYPE_STRING:
{
int len;
/* Demarshal the length, which does NOT include
* nul termination
*/
len = demarshal_and_validate_len (str, byte_order, pos + 1, &pos);
if (len < 0)
return FALSE;
if (!validate_string (str, pos, len, end_pos))
return FALSE;
}
break;
case DBUS_TYPE_BYTE_ARRAY:
{
int len;
len = demarshal_and_validate_len (str, byte_order, pos + 1, &pos);
if (len < 0)
return FALSE;
*end_pos = pos + len;
}
break;
case DBUS_TYPE_INT32_ARRAY:
case DBUS_TYPE_UINT32_ARRAY:
{
int len;
len = demarshal_and_validate_len (str, byte_order, pos + 1, &pos);
if (len < 0)
return FALSE;
_dbus_assert (_DBUS_ALIGN_VALUE (pos, 4) == (unsigned int) pos);
*end_pos = pos + len * 4;
}
break;
case DBUS_TYPE_DOUBLE_ARRAY:
{
int len;
int align_8;
len = demarshal_and_validate_len (str, byte_order, pos + 1, &pos);
if (len < 0)
return FALSE;
align_8 = _DBUS_ALIGN_VALUE (pos, 8);
if (!_dbus_string_validate_nul (str, pos,
align_8 - pos))
{
_dbus_verbose ("double array alignment padding not initialized to nul\n");
return FALSE;
}
*end_pos = align_8 + len * 8;
}
break;
case DBUS_TYPE_STRING_ARRAY:
{
int len;
int i;
len = demarshal_and_validate_len (str, byte_order, pos + 1, &pos);
if (len < 0)
return FALSE;
for (i = 0; i < len; i++)
{
int str_len;
str_len = demarshal_and_validate_len (str, byte_order,
pos, &pos);
if (str_len < 0)
return FALSE;
if (!validate_string (str, pos, str_len, &pos))
return FALSE;
}
*end_pos = pos;
}
break;
default:
_dbus_warn ("Unknown message arg type %d\n", *data);
return FALSE;
}
if (*end_pos > _dbus_string_get_length (str))
return FALSE;
return TRUE;
}
/**
* If in verbose mode, print a block of binary data.
*
@ -1018,6 +1246,8 @@ _dbus_verbose_bytes (const unsigned char *data,
int i;
const unsigned char *aligned;
_dbus_assert (len >= 0);
/* Print blanks on first row if appropriate */
aligned = _DBUS_ALIGN_ADDRESS (data, 4);
if (aligned > data)
@ -1026,7 +1256,7 @@ _dbus_verbose_bytes (const unsigned char *data,
if (aligned != data)
{
_dbus_verbose ("%5d\t%p: ", - (data - aligned), aligned);
_dbus_verbose ("%4d\t%p: ", - (data - aligned), aligned);
while (aligned != data)
{
_dbus_verbose (" ");
@ -1040,7 +1270,7 @@ _dbus_verbose_bytes (const unsigned char *data,
{
if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
{
_dbus_verbose ("%5d\t%p: ",
_dbus_verbose ("%4d\t%p: ",
i, &data[i]);
}
@ -1056,9 +1286,16 @@ _dbus_verbose_bytes (const unsigned char *data,
if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
{
if (i > 3)
_dbus_verbose ("big: %d little: %d",
_dbus_verbose ("BE: %d LE: %d",
_dbus_unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]),
_dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4]));
if (i > 7 &&
_DBUS_ALIGN_ADDRESS (&data[i], 8) == &data[i])
{
_dbus_verbose (" dbl: %g",
*(double*)&data[i-8]);
}
_dbus_verbose ("\n");
}
@ -1080,7 +1317,27 @@ _dbus_verbose_bytes_of_string (const DBusString *str,
int len)
{
const char *d;
int real_len;
real_len = _dbus_string_get_length (str);
_dbus_assert (start >= 0);
if (start > real_len)
{
_dbus_verbose (" [%d,%d) is not inside string of length %d\n",
start, len, real_len);
return;
}
if ((start + len) > real_len)
{
_dbus_verbose (" [%d,%d) extends outside string of length %d\n",
start, len, real_len);
len = real_len - start;
}
_dbus_string_get_const_data_len (str, &d, start, len);
_dbus_verbose_bytes (d, len);

View file

@ -124,54 +124,57 @@ dbus_bool_t _dbus_marshal_string_array (DBusString *str,
const char **value,
int len);
double _dbus_demarshal_double (DBusString *str,
int byte_order,
int pos,
int *new_pos);
dbus_int32_t _dbus_demarshal_int32 (DBusString *str,
int byte_order,
int pos,
int *new_pos);
dbus_uint32_t _dbus_demarshal_uint32 (DBusString *str,
int byte_order,
int pos,
int *new_pos);
char * _dbus_demarshal_string (DBusString *str,
int byte_order,
int pos,
int *new_pos);
unsigned char *_dbus_demarshal_byte_array (DBusString *str,
int byte_order,
int pos,
int *new_pos,
int *array_len);
dbus_int32_t *_dbus_demarshal_int32_array (DBusString *str,
int byte_order,
int pos,
int *new_pos,
int *array_len);
dbus_uint32_t *_dbus_demarshal_uint32_array (DBusString *str,
int byte_order,
int pos,
int *new_pos,
int *array_len);
double *_dbus_demarshal_double_array (DBusString *str,
int byte_order,
int pos,
int *new_pos,
int *array_len);
char **_dbus_demarshal_string_array (DBusString *str,
int byte_order,
int pos,
int *new_pos,
int *array_len);
dbus_bool_t _dbus_marshal_get_field_end_pos (DBusString *str,
int byte_order,
int pos,
int *end_pos);
double _dbus_demarshal_double (const DBusString *str,
int byte_order,
int pos,
int *new_pos);
dbus_int32_t _dbus_demarshal_int32 (const DBusString *str,
int byte_order,
int pos,
int *new_pos);
dbus_uint32_t _dbus_demarshal_uint32 (const DBusString *str,
int byte_order,
int pos,
int *new_pos);
char * _dbus_demarshal_string (const DBusString *str,
int byte_order,
int pos,
int *new_pos);
unsigned char *_dbus_demarshal_byte_array (const DBusString *str,
int byte_order,
int pos,
int *new_pos,
int *array_len);
dbus_int32_t * _dbus_demarshal_int32_array (const DBusString *str,
int byte_order,
int pos,
int *new_pos,
int *array_len);
dbus_uint32_t *_dbus_demarshal_uint32_array (const DBusString *str,
int byte_order,
int pos,
int *new_pos,
int *array_len);
double * _dbus_demarshal_double_array (const DBusString *str,
int byte_order,
int pos,
int *new_pos,
int *array_len);
char ** _dbus_demarshal_string_array (const DBusString *str,
int byte_order,
int pos,
int *new_pos,
int *array_len);
dbus_bool_t _dbus_marshal_get_arg_end_pos (const DBusString *str,
int byte_order,
int pos,
int *end_pos);
dbus_bool_t _dbus_marshal_validate_arg (const DBusString *str,
int byte_order,
int pos,
int *end_pos);
#endif /* DBUS_PROTOCOL_H */

View file

@ -91,6 +91,7 @@ struct DBusMessage
HeaderField header_fields[FIELD_LAST]; /**< Track the location
* of each field in "header"
*/
int header_padding; /**< bytes of alignment in header */
DBusString body; /**< Body network data. */
@ -137,6 +138,27 @@ _dbus_message_get_network_data (DBusMessage *message,
*body = &message->body;
}
static void
clear_header_padding (DBusMessage *message)
{
_dbus_string_shorten (&message->header,
message->header_padding);
message->header_padding = 0;
}
static dbus_bool_t
append_header_padding (DBusMessage *message)
{
int old_len;
old_len = _dbus_string_get_length (&message->header);
if (!_dbus_string_align_length (&message->header, 8))
return FALSE;
message->header_padding = _dbus_string_get_length (&message->header) - old_len;
return TRUE;
}
static void
adjust_field_offsets (DBusMessage *message,
int offsets_after,
@ -209,6 +231,8 @@ append_int_field (DBusMessage *message,
int orig_len;
_dbus_assert (!message->locked);
clear_header_padding (message);
orig_len = _dbus_string_get_length (&message->header);
@ -227,15 +251,24 @@ append_int_field (DBusMessage *message,
message->header_fields[FIELD_REPLY_SERIAL].offset =
_dbus_string_get_length (&message->header);
if (!_dbus_marshal_int32 (&message->header, DBUS_COMPILER_BYTE_ORDER,
if (!_dbus_marshal_int32 (&message->header, message->byte_order,
value))
goto failed;
if (!append_header_padding (message))
goto failed;
return TRUE;
failed:
message->header_fields[field].offset = -1;
_dbus_string_set_length (&message->header, orig_len);
/* this must succeed because it was allocated on function entry and
* DBusString doesn't ever realloc smaller
*/
if (!append_header_padding (message))
_dbus_assert_not_reached ("failed to reappend header padding");
return FALSE;
}
@ -248,6 +281,8 @@ append_string_field (DBusMessage *message,
int orig_len;
_dbus_assert (!message->locked);
clear_header_padding (message);
orig_len = _dbus_string_get_length (&message->header);
@ -266,15 +301,25 @@ append_string_field (DBusMessage *message,
message->header_fields[field].offset =
_dbus_string_get_length (&message->header);
if (!_dbus_marshal_string (&message->header, DBUS_COMPILER_BYTE_ORDER,
if (!_dbus_marshal_string (&message->header, message->byte_order,
value))
goto failed;
if (!append_header_padding (message))
goto failed;
return TRUE;
failed:
message->header_fields[field].offset = -1;
_dbus_string_set_length (&message->header, orig_len);
/* this must succeed because it was allocated on function entry and
* DBusString doesn't ever realloc smaller
*/
if (!append_header_padding (message))
_dbus_assert_not_reached ("failed to reappend header padding");
return FALSE;
}
@ -290,6 +335,8 @@ delete_int_field (DBusMessage *message,
if (offset < 0)
return;
clear_header_padding (message);
/* The field typecode and name take up 8 bytes */
_dbus_string_delete (&message->header,
offset - 8,
@ -300,6 +347,8 @@ delete_int_field (DBusMessage *message,
adjust_field_offsets (message,
offset - 8,
- 12);
append_header_padding (message);
}
static void
@ -316,6 +365,8 @@ delete_string_field (DBusMessage *message,
if (offset < 0)
return;
clear_header_padding (message);
get_string_field (message, field, &len);
/* The field typecode and name take up 8 bytes, and the nul
@ -332,6 +383,8 @@ delete_string_field (DBusMessage *message,
adjust_field_offsets (message,
offset - 8,
- delete_len);
append_header_padding (message);
}
static dbus_bool_t
@ -528,8 +581,8 @@ static dbus_bool_t
dbus_message_create_header (DBusMessage *message,
const char *service,
const char *name)
{
if (!_dbus_string_append_byte (&message->header, DBUS_COMPILER_BYTE_ORDER))
{
if (!_dbus_string_append_byte (&message->header, message->byte_order))
return FALSE;
if (!_dbus_string_append_len (&message->header, "\0\0\0", 3))
@ -563,7 +616,7 @@ dbus_message_create_header (DBusMessage *message,
DBUS_HEADER_FIELD_NAME,
name))
return FALSE;
return TRUE;
}
@ -969,7 +1022,7 @@ dbus_message_append_int32 (DBusMessage *message,
}
return _dbus_marshal_int32 (&message->body,
DBUS_COMPILER_BYTE_ORDER, value);
message->byte_order, value);
}
/**
@ -992,7 +1045,7 @@ dbus_message_append_uint32 (DBusMessage *message,
}
return _dbus_marshal_uint32 (&message->body,
DBUS_COMPILER_BYTE_ORDER, value);
message->byte_order, value);
}
/**
@ -1015,7 +1068,7 @@ dbus_message_append_double (DBusMessage *message,
}
return _dbus_marshal_double (&message->body,
DBUS_COMPILER_BYTE_ORDER, value);
message->byte_order, value);
}
/**
@ -1038,7 +1091,7 @@ dbus_message_append_string (DBusMessage *message,
}
return _dbus_marshal_string (&message->body,
DBUS_COMPILER_BYTE_ORDER, value);
message->byte_order, value);
}
/**
@ -1063,7 +1116,7 @@ dbus_message_append_byte_array (DBusMessage *message,
}
return _dbus_marshal_byte_array (&message->body,
DBUS_COMPILER_BYTE_ORDER, value, len);
message->byte_order, value, len);
}
/**
@ -1088,7 +1141,7 @@ dbus_message_append_string_array (DBusMessage *message,
}
return _dbus_marshal_string_array (&message->body,
DBUS_COMPILER_BYTE_ORDER, value, len);
message->byte_order, value, len);
}
/**
@ -1342,9 +1395,9 @@ dbus_message_iter_has_next (DBusMessageIter *iter)
{
int end_pos;
if (!_dbus_marshal_get_field_end_pos (&iter->message->body,
iter->message->byte_order,
iter->pos, &end_pos))
if (!_dbus_marshal_get_arg_end_pos (&iter->message->body,
iter->message->byte_order,
iter->pos, &end_pos))
return FALSE;
if (end_pos >= _dbus_string_get_length (&iter->message->body))
@ -1364,8 +1417,9 @@ dbus_message_iter_next (DBusMessageIter *iter)
{
int end_pos;
if (!_dbus_marshal_get_field_end_pos (&iter->message->body, iter->message->byte_order,
iter->pos, &end_pos))
if (!_dbus_marshal_get_arg_end_pos (&iter->message->body,
iter->message->byte_order,
iter->pos, &end_pos))
return FALSE;
if (end_pos >= _dbus_string_get_length (&iter->message->body))
@ -1570,6 +1624,12 @@ dbus_message_get_sender (DBusMessage *message)
*
*/
/* we definitely use signed ints for sizes, so don't exceed
* _DBUS_INT_MAX; and add 16 for paranoia, since a message
* over 128M is pretty nuts anyhow.
*/
#define MAX_SANE_MESSAGE_SIZE (_DBUS_INT_MAX/16)
/**
* Implementation details of DBusMessageLoader.
* All members are private.
@ -1724,18 +1784,11 @@ _dbus_message_loader_get_buffer (DBusMessageLoader *loader,
#define DBUS_HEADER_FIELD_SENDER_AS_UINT32 \
FOUR_CHARS_TO_UINT32 ('s', 'n', 'd', 'r')
/* FIXME should be using DBusString for the stuff we demarshal. char*
* evil. Also, out of memory handling here seems suboptimal.
* Should probably report it as a distinct error from "corrupt message,"
* so we can postpone parsing this message. Also, we aren't
* checking for demarshal failure everywhere.
*/
static dbus_bool_t
decode_header_data (DBusString *data,
int header_len,
int byte_order,
HeaderField fields[FIELD_LAST])
decode_header_data (const DBusString *data,
int header_len,
int byte_order,
HeaderField fields[FIELD_LAST])
{
const char *field;
int pos, new_pos;
@ -1743,7 +1796,7 @@ decode_header_data (DBusString *data,
if (header_len < 16)
return FALSE;
i = 0;
while (i < FIELD_LAST)
{
@ -1755,9 +1808,14 @@ decode_header_data (DBusString *data,
fields[FIELD_BODY_LENGTH].offset = 8;
fields[FIELD_CLIENT_SERIAL].offset = 12;
/* Now handle the fields */
/* Now handle the named fields. A real named field is at least 4
* bytes for the name, plus a type code (1 byte) plus padding. So
* if we have less than 8 bytes left, it must be alignment padding,
* not a field. While >= 8 bytes can't be entirely alignment
* padding.
*/
pos = 16;
while (pos < header_len)
while ((pos + 7) < header_len)
{
pos = _DBUS_ALIGN_VALUE (pos, 4);
@ -1833,8 +1891,7 @@ decode_header_data (DBusString *data,
field[0], field[1], field[2], field[3]);
}
/* This function has to validate the fields */
if (!_dbus_marshal_get_field_end_pos (data, byte_order, pos, &new_pos))
if (!_dbus_marshal_validate_arg (data, byte_order, pos, &new_pos))
return FALSE;
if (new_pos > header_len)
@ -1842,6 +1899,19 @@ decode_header_data (DBusString *data,
pos = new_pos;
}
if (pos < header_len)
{
/* Alignment padding, verify that it's nul */
_dbus_assert ((header_len - pos) < 8);
if (!_dbus_string_validate_nul (data,
pos, (header_len - pos)))
{
_dbus_verbose ("header alignment padding is not nul\n");
return FALSE;
}
}
return TRUE;
}
@ -1893,6 +1963,22 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader,
header_len = _dbus_unpack_int32 (byte_order, header_data + 4);
body_len = _dbus_unpack_int32 (byte_order, header_data + 8);
if (header_len < 16 || body_len < 0)
{
_dbus_verbose ("Message had broken too-small header or body len %d %d\n",
header_len, body_len);
loader->corrupted = TRUE;
return;
}
if (_DBUS_ALIGN_VALUE (header_len, 8) != (unsigned int) header_len)
{
_dbus_verbose ("header length %d is not aligned to 8 bytes\n",
header_len);
loader->corrupted = TRUE;
return;
}
if (header_len + body_len > loader->max_message_size)
{
_dbus_verbose ("Message claimed length header = %d body = %d exceeds max message length %d\n",
@ -1905,22 +1991,47 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader,
{
HeaderField fields[FIELD_LAST];
int i;
/* FIXME right now if this doesn't have enough memory, the
* loader becomes corrupted. Instead we should just not
* parse this message for now.
*/
int next_arg;
if (!decode_header_data (&loader->data, header_len, byte_order,
fields))
{
loader->corrupted = TRUE;
return;
}
next_arg = header_len;
while (next_arg < (header_len + body_len))
{
int prev = next_arg;
if (!_dbus_marshal_validate_arg (&loader->data,
byte_order,
next_arg,
&next_arg))
{
loader->corrupted = TRUE;
return;
}
_dbus_assert (next_arg > prev);
}
if (next_arg > (header_len + body_len))
{
_dbus_verbose ("end of last arg at %d but message has len %d+%d=%d\n",
next_arg, header_len, body_len,
header_len + body_len);
loader->corrupted = TRUE;
return;
}
message = dbus_message_new_empty_header ();
if (message == NULL)
break; /* ugh, postpone this I guess. */
message->byte_order = byte_order;
/* Copy in the offsets we found */
i = 0;
while (i < FIELD_LAST)
@ -2012,6 +2123,12 @@ void
_dbus_message_loader_set_max_message_size (DBusMessageLoader *loader,
long size)
{
if (size > MAX_SANE_MESSAGE_SIZE)
{
_dbus_verbose ("clamping requested max message size %ld to %d\n",
size, MAX_SANE_MESSAGE_SIZE);
size = MAX_SANE_MESSAGE_SIZE;
}
loader->max_message_size = size;
}

View file

@ -608,7 +608,7 @@ _dbus_string_align_length (DBusString *str,
int delta;
DBUS_STRING_PREAMBLE (str);
_dbus_assert (alignment >= 1);
_dbus_assert (alignment <= 16); /* arbitrary */
_dbus_assert (alignment <= 8); /* it has to be a bug if > 8 */
new_len = _DBUS_ALIGN_VALUE (real->len, alignment);
@ -1843,6 +1843,65 @@ _dbus_string_validate_ascii (const DBusString *str,
return TRUE;
}
/**
* Checks that the given range of the string
* is valid UTF-8. If the given range is not contained
* in the string, returns #FALSE. If the string
* contains any nul bytes in the given range, returns
* #FALSE.
*
* @todo right now just calls _dbus_string_validate_ascii()
*
* @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 all valid UTF-8
*/
dbus_bool_t
_dbus_string_validate_utf8 (const DBusString *str,
int start,
int len)
{
/* FIXME actually validate UTF-8 */
return _dbus_string_validate_ascii (str, start, len);
}
/**
* Checks that the given range of the string
* is all nul bytes. If the given range is
* not contained in the string, returns #FALSE.
*
* @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 all nul bytes
*/
dbus_bool_t
_dbus_string_validate_nul (const DBusString *str,
int start,
int len)
{
const unsigned char *s;
const unsigned char *end;
DBUS_CONST_STRING_PREAMBLE (str);
_dbus_assert (start >= 0);
_dbus_assert (len >= 0);
if ((start + len) > real->len)
return FALSE;
s = real->str + start;
end = s + len;
while (s != end)
{
if (*s != '\0')
return FALSE;
++s;
}
return TRUE;
}
/** @} */
#ifdef DBUS_BUILD_TESTS

View file

@ -181,6 +181,14 @@ dbus_bool_t _dbus_string_validate_ascii (const DBusString *str,
int start,
int len);
dbus_bool_t _dbus_string_validate_utf8 (const DBusString *str,
int start,
int len);
dbus_bool_t _dbus_string_validate_nul (const DBusString *str,
int start,
int len);
DBUS_END_DECLS;
#endif /* DBUS_STRING_H */

View file

@ -5,7 +5,7 @@ OPPOSITE_ENDIAN
## VALID_HEADER includes a LENGTH Header and LENGTH Body
VALID_HEADER
FIELD_NAME repl
FIELD_NAME rply
TYPE INT32
INT32 10000
@ -17,6 +17,7 @@ FIELD_NAME unkn
TYPE INT32
INT32 0xfeeb
ALIGN 8
END_LENGTH Header
START_LENGTH Body

View file

@ -9,6 +9,7 @@ LENGTH Header
LENGTH Body
## client serial
INT32 7
ALIGN 8
END_LENGTH Header
START_LENGTH Body
END_LENGTH Body

View file

@ -2,6 +2,7 @@
## VALID_HEADER includes a LENGTH Header and LENGTH Body
VALID_HEADER
ALIGN 8
END_LENGTH Header
START_LENGTH Body
END_LENGTH Body