mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-07-30 22:03:29 +02:00
gdbusmessage: Limit recursion of variants in D-Bus messages
This is the analogue of commit 7c4e6e9fbe
, but applied to the
`GDBusMessage` parser, which does its own top-level parsing of the
variant format in D-Bus messages.
Previously, this code allowed arbitrary recursion of variant containers,
which could lead to a stack overflow. Now, that recursion is limited to
64 levels, as per the D-Bus specification:
https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling-signature
This includes a new unit test.
oss-fuzz#14870
Signed-off-by: Philip Withnall <withnall@endlessm.com>
This commit is contained in:
@@ -58,6 +58,10 @@
|
||||
|
||||
#include "glibintl.h"
|
||||
|
||||
/* See https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling-signature
|
||||
* This is 64 containers plus 1 value within them. */
|
||||
#define G_DBUS_MAX_TYPE_DEPTH (64 + 1)
|
||||
|
||||
typedef struct _GMemoryBuffer GMemoryBuffer;
|
||||
struct _GMemoryBuffer
|
||||
{
|
||||
@@ -1439,6 +1443,7 @@ read_bytes (GMemoryBuffer *mbuf,
|
||||
static GVariant *
|
||||
parse_value_from_blob (GMemoryBuffer *buf,
|
||||
const GVariantType *type,
|
||||
guint max_depth,
|
||||
gboolean just_align,
|
||||
guint indent,
|
||||
GError **error)
|
||||
@@ -1450,6 +1455,15 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
||||
#endif /* DEBUG_SERIALIZER */
|
||||
const gchar *type_string;
|
||||
|
||||
if (max_depth == 0)
|
||||
{
|
||||
g_set_error_literal (&local_error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_ARGUMENT,
|
||||
_("Value nested too deeply"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
type_string = g_variant_type_peek_string (type);
|
||||
|
||||
#ifdef DEBUG_SERIALIZER
|
||||
@@ -1687,6 +1701,17 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (max_depth == 1)
|
||||
{
|
||||
/* If we had recursed into parse_value_from_blob() again to
|
||||
* parse the array values, this would have been emitted. */
|
||||
g_set_error_literal (&local_error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_ARGUMENT,
|
||||
_("Value nested too deeply"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ensure_input_padding (buf, fixed_size);
|
||||
array_data = read_bytes (buf, array_len, &local_error);
|
||||
if (array_data == NULL)
|
||||
@@ -1714,6 +1739,7 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
||||
GVariant *item G_GNUC_UNUSED /* when compiling with G_DISABLE_ASSERT */;
|
||||
item = parse_value_from_blob (buf,
|
||||
element_type,
|
||||
max_depth - 1,
|
||||
TRUE,
|
||||
indent + 2,
|
||||
NULL);
|
||||
@@ -1728,6 +1754,7 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
||||
GVariant *item;
|
||||
item = parse_value_from_blob (buf,
|
||||
element_type,
|
||||
max_depth - 1,
|
||||
FALSE,
|
||||
indent + 2,
|
||||
&local_error);
|
||||
@@ -1767,6 +1794,7 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
||||
key_type = g_variant_type_key (type);
|
||||
key = parse_value_from_blob (buf,
|
||||
key_type,
|
||||
max_depth - 1,
|
||||
FALSE,
|
||||
indent + 2,
|
||||
&local_error);
|
||||
@@ -1775,6 +1803,7 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
||||
value_type = g_variant_type_value (type);
|
||||
value = parse_value_from_blob (buf,
|
||||
value_type,
|
||||
max_depth - 1,
|
||||
FALSE,
|
||||
indent + 2,
|
||||
&local_error);
|
||||
@@ -1809,6 +1838,7 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
||||
GVariant *item;
|
||||
item = parse_value_from_blob (buf,
|
||||
element_type,
|
||||
max_depth - 1,
|
||||
FALSE,
|
||||
indent + 2,
|
||||
&local_error);
|
||||
@@ -1855,9 +1885,26 @@ parse_value_from_blob (GMemoryBuffer *buf,
|
||||
sig);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (max_depth <= g_variant_type_string_get_depth_ (sig))
|
||||
{
|
||||
/* Catch the type nesting being too deep without having to
|
||||
* parse the data. We don’t have to check this for static
|
||||
* container types (like arrays and tuples, above) because
|
||||
* the g_variant_type_string_is_valid() check performed before
|
||||
* the initial parse_value_from_blob() call should check the
|
||||
* static type nesting. */
|
||||
g_set_error_literal (&local_error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_ARGUMENT,
|
||||
_("Value nested too deeply"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
variant_type = g_variant_type_new (sig);
|
||||
value = parse_value_from_blob (buf,
|
||||
variant_type,
|
||||
max_depth - 1,
|
||||
FALSE,
|
||||
indent + 2,
|
||||
&local_error);
|
||||
@@ -2095,6 +2142,7 @@ g_dbus_message_new_from_blob (guchar *blob,
|
||||
#endif /* DEBUG_SERIALIZER */
|
||||
headers = parse_value_from_blob (&mbuf,
|
||||
G_VARIANT_TYPE ("a{yv}"),
|
||||
G_DBUS_MAX_TYPE_DEPTH + 2 /* for the a{yv} */,
|
||||
FALSE,
|
||||
2,
|
||||
error);
|
||||
@@ -2166,6 +2214,7 @@ g_dbus_message_new_from_blob (guchar *blob,
|
||||
#endif /* DEBUG_SERIALIZER */
|
||||
message->body = parse_value_from_blob (&mbuf,
|
||||
variant_type,
|
||||
G_DBUS_MAX_TYPE_DEPTH + 1 /* for the surrounding tuple */,
|
||||
FALSE,
|
||||
2,
|
||||
error);
|
||||
|
Reference in New Issue
Block a user