mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
Merge branch '3093-gdbus-header-validation' into 'main'
gdbusmessage: Validate the types of all known message headers Closes #3093 See merge request GNOME/glib!3748
This commit is contained in:
commit
6900e0450f
@ -1283,17 +1283,225 @@ get_type_fixed_size (const GVariantType *type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
message_type_to_string (GDBusMessageType message_type)
|
||||||
|
{
|
||||||
|
switch (message_type)
|
||||||
|
{
|
||||||
|
case G_DBUS_MESSAGE_TYPE_INVALID:
|
||||||
|
return "INVALID";
|
||||||
|
case G_DBUS_MESSAGE_TYPE_METHOD_CALL:
|
||||||
|
return "METHOD_CALL";
|
||||||
|
case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
|
||||||
|
return "METHOD_RETURN";
|
||||||
|
case G_DBUS_MESSAGE_TYPE_ERROR:
|
||||||
|
return "ERROR";
|
||||||
|
case G_DBUS_MESSAGE_TYPE_SIGNAL:
|
||||||
|
return "SIGNAL";
|
||||||
|
default:
|
||||||
|
return "unknown-type";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
message_header_field_to_string (GDBusMessageHeaderField field)
|
||||||
|
{
|
||||||
|
switch (field)
|
||||||
|
{
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_INVALID:
|
||||||
|
return "INVALID";
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_PATH:
|
||||||
|
return "PATH";
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE:
|
||||||
|
return "INTERFACE";
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_MEMBER:
|
||||||
|
return "MEMBER";
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME:
|
||||||
|
return "ERROR_NAME";
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL:
|
||||||
|
return "REPLY_SERIAL";
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION:
|
||||||
|
return "DESTINATION";
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_SENDER:
|
||||||
|
return "SENDER";
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE:
|
||||||
|
return "SIGNATURE";
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS:
|
||||||
|
return "NUM_UNIX_FDS";
|
||||||
|
default:
|
||||||
|
return "unknown-field";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
validate_header (GDBusMessage *message,
|
||||||
|
GDBusMessageHeaderField field,
|
||||||
|
GVariant *header_value,
|
||||||
|
const GVariantType *expected_type,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_assert (header_value != NULL);
|
||||||
|
|
||||||
|
if (!g_variant_is_of_type (header_value, expected_type))
|
||||||
|
{
|
||||||
|
char *expected_type_string = g_variant_type_dup_string (expected_type);
|
||||||
|
g_set_error (error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_ARGUMENT,
|
||||||
|
_("%s message: %s header field is invalid; expected a value of type ‘%s’"),
|
||||||
|
message_type_to_string (message->type),
|
||||||
|
message_header_field_to_string (field),
|
||||||
|
expected_type_string);
|
||||||
|
g_free (expected_type_string);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
require_header (GDBusMessage *message,
|
||||||
|
GDBusMessageHeaderField field,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GVariant *header_value = g_dbus_message_get_header (message, field);
|
||||||
|
|
||||||
|
if (header_value == NULL)
|
||||||
|
{
|
||||||
|
g_set_error (error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_ARGUMENT,
|
||||||
|
_("%s message: %s header field is missing or invalid"),
|
||||||
|
message_type_to_string (message->type),
|
||||||
|
message_header_field_to_string (field));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implement the validation rules given in
|
||||||
|
* https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-header-fields */
|
||||||
static gboolean
|
static gboolean
|
||||||
validate_headers (GDBusMessage *message,
|
validate_headers (GDBusMessage *message,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
|
GHashTableIter headers_iter;
|
||||||
|
gpointer key;
|
||||||
|
GVariant *header_value;
|
||||||
|
|
||||||
g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
|
g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
|
||||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||||
|
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
|
|
||||||
|
/* Validate the types of all known headers. */
|
||||||
|
g_hash_table_iter_init (&headers_iter, message->headers);
|
||||||
|
while (g_hash_table_iter_next (&headers_iter, &key, (gpointer) &header_value))
|
||||||
|
{
|
||||||
|
GDBusMessageHeaderField field_type = GPOINTER_TO_INT (key);
|
||||||
|
|
||||||
|
switch (field_type)
|
||||||
|
{
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_INVALID:
|
||||||
|
/* The invalid header must be rejected as per
|
||||||
|
* https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-header-fields */
|
||||||
|
g_set_error (error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_ARGUMENT,
|
||||||
|
_("%s message: INVALID header field supplied"),
|
||||||
|
message_type_to_string (message->type));
|
||||||
|
goto out;
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_PATH:
|
||||||
|
if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_OBJECT_PATH, error))
|
||||||
|
goto out;
|
||||||
|
if (g_strcmp0 (g_variant_get_string (header_value, NULL), "/org/freedesktop/DBus/Local") == 0)
|
||||||
|
{
|
||||||
|
g_set_error (error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_ARGUMENT,
|
||||||
|
_("%s message: PATH header field is using the reserved value /org/freedesktop/DBus/Local"),
|
||||||
|
message_type_to_string (message->type));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE:
|
||||||
|
if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_STRING, error))
|
||||||
|
goto out;
|
||||||
|
if (!g_dbus_is_interface_name (g_variant_get_string (header_value, NULL)))
|
||||||
|
{
|
||||||
|
g_set_error (error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_ARGUMENT,
|
||||||
|
_("%s message: INTERFACE header field does not contain a valid interface name"),
|
||||||
|
message_type_to_string (message->type));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (g_strcmp0 (g_variant_get_string (header_value, NULL), "org.freedesktop.DBus.Local") == 0)
|
||||||
|
{
|
||||||
|
g_set_error (error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_ARGUMENT,
|
||||||
|
_("%s message: INTERFACE header field is using the reserved value org.freedesktop.DBus.Local"),
|
||||||
|
message_type_to_string (message->type));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_MEMBER:
|
||||||
|
if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_STRING, error))
|
||||||
|
goto out;
|
||||||
|
if (!g_dbus_is_member_name (g_variant_get_string (header_value, NULL)))
|
||||||
|
{
|
||||||
|
g_set_error (error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_ARGUMENT,
|
||||||
|
_("%s message: MEMBER header field does not contain a valid member name"),
|
||||||
|
message_type_to_string (message->type));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME:
|
||||||
|
if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_STRING, error))
|
||||||
|
goto out;
|
||||||
|
if (!g_dbus_is_error_name (g_variant_get_string (header_value, NULL)))
|
||||||
|
{
|
||||||
|
g_set_error (error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_ARGUMENT,
|
||||||
|
_("%s message: ERROR_NAME header field does not contain a valid error name"),
|
||||||
|
message_type_to_string (message->type));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL:
|
||||||
|
if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_UINT32, error))
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION:
|
||||||
|
if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_STRING, error))
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_SENDER:
|
||||||
|
if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_STRING, error))
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE:
|
||||||
|
if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_SIGNATURE, error))
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS:
|
||||||
|
if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_UINT32, error))
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Ignore unknown fields as per
|
||||||
|
* https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-header-fields. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for message-type-specific required headers. */
|
||||||
switch (message->type)
|
switch (message->type)
|
||||||
{
|
{
|
||||||
case G_DBUS_MESSAGE_TYPE_INVALID:
|
case G_DBUS_MESSAGE_TYPE_INVALID:
|
||||||
@ -1302,102 +1510,29 @@ validate_headers (GDBusMessage *message,
|
|||||||
G_IO_ERROR_INVALID_ARGUMENT,
|
G_IO_ERROR_INVALID_ARGUMENT,
|
||||||
_("type is INVALID"));
|
_("type is INVALID"));
|
||||||
goto out;
|
goto out;
|
||||||
break;
|
|
||||||
|
|
||||||
case G_DBUS_MESSAGE_TYPE_METHOD_CALL:
|
case G_DBUS_MESSAGE_TYPE_METHOD_CALL:
|
||||||
{
|
if (!require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH, error) ||
|
||||||
GVariant *path_variant = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH);
|
!require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER, error))
|
||||||
GVariant *member_variant = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER);
|
goto out;
|
||||||
|
|
||||||
if (path_variant == NULL ||
|
|
||||||
!g_variant_is_of_type (path_variant, G_VARIANT_TYPE_OBJECT_PATH) ||
|
|
||||||
member_variant == NULL ||
|
|
||||||
!g_variant_is_of_type (member_variant, G_VARIANT_TYPE_STRING) ||
|
|
||||||
!g_dbus_is_member_name (g_variant_get_string (member_variant, NULL)))
|
|
||||||
{
|
|
||||||
g_set_error_literal (error,
|
|
||||||
G_IO_ERROR,
|
|
||||||
G_IO_ERROR_INVALID_ARGUMENT,
|
|
||||||
_("METHOD_CALL message: PATH or MEMBER header field is missing or invalid"));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
|
case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
|
||||||
{
|
if (!require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, error))
|
||||||
GVariant *reply_serial_variant = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL);
|
goto out;
|
||||||
|
|
||||||
if (reply_serial_variant == NULL ||
|
|
||||||
!g_variant_is_of_type (reply_serial_variant, G_VARIANT_TYPE_UINT32))
|
|
||||||
{
|
|
||||||
g_set_error_literal (error,
|
|
||||||
G_IO_ERROR,
|
|
||||||
G_IO_ERROR_INVALID_ARGUMENT,
|
|
||||||
_("METHOD_RETURN message: REPLY_SERIAL header field is missing or invalid"));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case G_DBUS_MESSAGE_TYPE_ERROR:
|
case G_DBUS_MESSAGE_TYPE_ERROR:
|
||||||
{
|
if (!require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME, error) ||
|
||||||
GVariant *error_name_variant = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME);
|
!require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, error))
|
||||||
GVariant *reply_serial_variant = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL);
|
goto out;
|
||||||
|
|
||||||
if (error_name_variant == NULL ||
|
|
||||||
!g_variant_is_of_type (error_name_variant, G_VARIANT_TYPE_STRING) ||
|
|
||||||
!g_dbus_is_error_name (g_variant_get_string (error_name_variant, NULL)) ||
|
|
||||||
reply_serial_variant == NULL ||
|
|
||||||
!g_variant_is_of_type (reply_serial_variant, G_VARIANT_TYPE_UINT32))
|
|
||||||
{
|
|
||||||
g_set_error_literal (error,
|
|
||||||
G_IO_ERROR,
|
|
||||||
G_IO_ERROR_INVALID_ARGUMENT,
|
|
||||||
_("ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing or invalid"));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case G_DBUS_MESSAGE_TYPE_SIGNAL:
|
case G_DBUS_MESSAGE_TYPE_SIGNAL:
|
||||||
{
|
if (!require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH, error) ||
|
||||||
GVariant *path_variant = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH);
|
!require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE, error) ||
|
||||||
GVariant *interface_variant = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE);
|
!require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER, error))
|
||||||
GVariant *member_variant = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER);
|
goto out;
|
||||||
|
|
||||||
if (path_variant == NULL ||
|
|
||||||
!g_variant_is_of_type (path_variant, G_VARIANT_TYPE_OBJECT_PATH) ||
|
|
||||||
interface_variant == NULL ||
|
|
||||||
!g_variant_is_of_type (interface_variant, G_VARIANT_TYPE_STRING) ||
|
|
||||||
!g_dbus_is_interface_name (g_variant_get_string (interface_variant, NULL)) ||
|
|
||||||
member_variant == NULL ||
|
|
||||||
!g_variant_is_of_type (member_variant, G_VARIANT_TYPE_STRING) ||
|
|
||||||
!g_dbus_is_member_name (g_variant_get_string (member_variant, NULL)))
|
|
||||||
{
|
|
||||||
g_set_error_literal (error,
|
|
||||||
G_IO_ERROR,
|
|
||||||
G_IO_ERROR_INVALID_ARGUMENT,
|
|
||||||
_("SIGNAL message: PATH, INTERFACE or MEMBER header field is missing or invalid"));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (g_strcmp0 (g_dbus_message_get_path (message), "/org/freedesktop/DBus/Local") == 0)
|
|
||||||
{
|
|
||||||
g_set_error_literal (error,
|
|
||||||
G_IO_ERROR,
|
|
||||||
G_IO_ERROR_INVALID_ARGUMENT,
|
|
||||||
_("SIGNAL message: The PATH header field is using the reserved value /org/freedesktop/DBus/Local"));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (g_strcmp0 (g_dbus_message_get_interface (message), "org.freedesktop.DBus.Local") == 0)
|
|
||||||
{
|
|
||||||
g_set_error_literal (error,
|
|
||||||
G_IO_ERROR,
|
|
||||||
G_IO_ERROR_INVALID_ARGUMENT,
|
|
||||||
_("SIGNAL message: The INTERFACE header field is using the reserved value org.freedesktop.DBus.Local"));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -914,19 +914,106 @@ test_message_serialize_header_checks (void)
|
|||||||
g_object_unref (message);
|
g_object_unref (message);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check that we can't serialize messages with SIGNATURE set to a non-signature-typed value
|
* check we can't serialize messages with an INVALID header
|
||||||
*/
|
*/
|
||||||
message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember");
|
message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember");
|
||||||
g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, g_variant_new_boolean (FALSE));
|
g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_INVALID, g_variant_new_boolean (FALSE));
|
||||||
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
||||||
|
|
||||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
||||||
g_assert_cmpstr (error->message, ==, "Signature header found but is not of type signature");
|
g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: INVALID header field supplied");
|
||||||
g_assert_null (blob);
|
g_assert_null (blob);
|
||||||
|
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
g_clear_object (&message);
|
g_clear_object (&message);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check that we can't serialize messages with various fields set to incorrectly typed values
|
||||||
|
*/
|
||||||
|
const struct
|
||||||
|
{
|
||||||
|
GDBusMessageHeaderField field;
|
||||||
|
const char *invalid_value; /* as a GVariant in text form */
|
||||||
|
const char *expected_error_message;
|
||||||
|
}
|
||||||
|
field_type_tests[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
G_DBUS_MESSAGE_HEADER_FIELD_PATH,
|
||||||
|
"'/correct/value/but/wrong/type'",
|
||||||
|
"Cannot serialize message: SIGNAL message: PATH header field is invalid; expected a value of type ‘o’"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE,
|
||||||
|
"@u 5",
|
||||||
|
"Cannot serialize message: SIGNAL message: INTERFACE header field is invalid; expected a value of type ‘s’"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE,
|
||||||
|
"'valid type, but not an interface name'",
|
||||||
|
"Cannot serialize message: SIGNAL message: INTERFACE header field does not contain a valid interface name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
G_DBUS_MESSAGE_HEADER_FIELD_MEMBER,
|
||||||
|
"@u 5",
|
||||||
|
"Cannot serialize message: SIGNAL message: MEMBER header field is invalid; expected a value of type ‘s’"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
G_DBUS_MESSAGE_HEADER_FIELD_MEMBER,
|
||||||
|
"'valid type, but not a member name'",
|
||||||
|
"Cannot serialize message: SIGNAL message: MEMBER header field does not contain a valid member name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME,
|
||||||
|
"@u 5",
|
||||||
|
"Cannot serialize message: SIGNAL message: ERROR_NAME header field is invalid; expected a value of type ‘s’"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME,
|
||||||
|
"'valid type, but not an error name'",
|
||||||
|
"Cannot serialize message: SIGNAL message: ERROR_NAME header field does not contain a valid error name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL,
|
||||||
|
"'oops'",
|
||||||
|
"Cannot serialize message: SIGNAL message: REPLY_SERIAL header field is invalid; expected a value of type ‘u’"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION,
|
||||||
|
"@u 5",
|
||||||
|
"Cannot serialize message: SIGNAL message: DESTINATION header field is invalid; expected a value of type ‘s’"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
G_DBUS_MESSAGE_HEADER_FIELD_SENDER,
|
||||||
|
"@u 5",
|
||||||
|
"Cannot serialize message: SIGNAL message: SENDER header field is invalid; expected a value of type ‘s’"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE,
|
||||||
|
"false",
|
||||||
|
"Cannot serialize message: SIGNAL message: SIGNATURE header field is invalid; expected a value of type ‘g’"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS,
|
||||||
|
"'five'",
|
||||||
|
"Cannot serialize message: SIGNAL message: NUM_UNIX_FDS header field is invalid; expected a value of type ‘u’"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < G_N_ELEMENTS (field_type_tests); i++)
|
||||||
|
{
|
||||||
|
message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember");
|
||||||
|
g_dbus_message_set_header (message, field_type_tests[i].field, g_variant_new_parsed (field_type_tests[i].invalid_value));
|
||||||
|
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
||||||
|
|
||||||
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
||||||
|
g_assert_cmpstr (error->message, ==, field_type_tests[i].expected_error_message);
|
||||||
|
g_assert_null (blob);
|
||||||
|
|
||||||
|
g_clear_error (&error);
|
||||||
|
g_clear_object (&message);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check we can't serialize signal messages with INTERFACE, PATH or MEMBER unset / set to reserved value
|
* check we can't serialize signal messages with INTERFACE, PATH or MEMBER unset / set to reserved value
|
||||||
*/
|
*/
|
||||||
@ -936,14 +1023,14 @@ test_message_serialize_header_checks (void)
|
|||||||
g_dbus_message_set_interface (message, NULL);
|
g_dbus_message_set_interface (message, NULL);
|
||||||
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
||||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
||||||
g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing or invalid");
|
g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: INTERFACE header field is missing or invalid");
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
g_assert_null (blob);
|
g_assert_null (blob);
|
||||||
/* interface reserved value => error */
|
/* interface reserved value => error */
|
||||||
g_dbus_message_set_interface (message, "org.freedesktop.DBus.Local");
|
g_dbus_message_set_interface (message, "org.freedesktop.DBus.Local");
|
||||||
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
||||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
||||||
g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: The INTERFACE header field is using the reserved value org.freedesktop.DBus.Local");
|
g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: INTERFACE header field is using the reserved value org.freedesktop.DBus.Local");
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
g_assert_null (blob);
|
g_assert_null (blob);
|
||||||
/* reset interface */
|
/* reset interface */
|
||||||
@ -953,14 +1040,14 @@ test_message_serialize_header_checks (void)
|
|||||||
g_dbus_message_set_path (message, NULL);
|
g_dbus_message_set_path (message, NULL);
|
||||||
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
||||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
||||||
g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing or invalid");
|
g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH header field is missing or invalid");
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
g_assert_null (blob);
|
g_assert_null (blob);
|
||||||
/* path reserved value => error */
|
/* path reserved value => error */
|
||||||
g_dbus_message_set_path (message, "/org/freedesktop/DBus/Local");
|
g_dbus_message_set_path (message, "/org/freedesktop/DBus/Local");
|
||||||
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
||||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
||||||
g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: The PATH header field is using the reserved value /org/freedesktop/DBus/Local");
|
g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH header field is using the reserved value /org/freedesktop/DBus/Local");
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
g_assert_null (blob);
|
g_assert_null (blob);
|
||||||
/* reset path */
|
/* reset path */
|
||||||
@ -970,7 +1057,7 @@ test_message_serialize_header_checks (void)
|
|||||||
g_dbus_message_set_member (message, NULL);
|
g_dbus_message_set_member (message, NULL);
|
||||||
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
||||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
||||||
g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing or invalid");
|
g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: MEMBER header field is missing or invalid");
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
g_assert_null (blob);
|
g_assert_null (blob);
|
||||||
/* reset member */
|
/* reset member */
|
||||||
@ -988,7 +1075,7 @@ test_message_serialize_header_checks (void)
|
|||||||
g_dbus_message_set_path (message, NULL);
|
g_dbus_message_set_path (message, NULL);
|
||||||
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
||||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
||||||
g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH or MEMBER header field is missing or invalid");
|
g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH header field is missing or invalid");
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
g_assert_null (blob);
|
g_assert_null (blob);
|
||||||
/* reset path */
|
/* reset path */
|
||||||
@ -998,7 +1085,7 @@ test_message_serialize_header_checks (void)
|
|||||||
g_dbus_message_set_member (message, NULL);
|
g_dbus_message_set_member (message, NULL);
|
||||||
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
||||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
||||||
g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH or MEMBER header field is missing or invalid");
|
g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: MEMBER header field is missing or invalid");
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
g_assert_null (blob);
|
g_assert_null (blob);
|
||||||
/* reset member */
|
/* reset member */
|
||||||
@ -1029,7 +1116,7 @@ test_message_serialize_header_checks (void)
|
|||||||
g_dbus_message_set_error_name (reply, NULL);
|
g_dbus_message_set_error_name (reply, NULL);
|
||||||
blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
||||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
||||||
g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing or invalid");
|
g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: ERROR_NAME header field is missing or invalid");
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
g_assert_null (blob);
|
g_assert_null (blob);
|
||||||
/* reset ERROR_NAME */
|
/* reset ERROR_NAME */
|
||||||
@ -1038,13 +1125,77 @@ test_message_serialize_header_checks (void)
|
|||||||
g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL);
|
g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL);
|
||||||
blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
|
||||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
||||||
g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing or invalid");
|
g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: REPLY_SERIAL header field is missing or invalid");
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
g_assert_null (blob);
|
g_assert_null (blob);
|
||||||
g_object_unref (reply);
|
g_object_unref (reply);
|
||||||
g_object_unref (message);
|
g_object_unref (message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_message_serialize_header_checks_valid (void)
|
||||||
|
{
|
||||||
|
GDBusMessage *message = NULL, *reply = NULL;
|
||||||
|
GError *local_error = NULL;
|
||||||
|
guchar *blob;
|
||||||
|
gsize blob_size;
|
||||||
|
|
||||||
|
g_test_summary ("Test that validation allows well-formed messages of all the different types");
|
||||||
|
|
||||||
|
/* Method call */
|
||||||
|
message = g_dbus_message_new_method_call ("Some.Name", "/the/path", "org.some.Interface", "TheMethod");
|
||||||
|
g_dbus_message_set_serial (message, 666);
|
||||||
|
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
|
||||||
|
g_assert_no_error (local_error);
|
||||||
|
g_assert_nonnull (blob);
|
||||||
|
g_free (blob);
|
||||||
|
|
||||||
|
/* Method return */
|
||||||
|
reply = g_dbus_message_new_method_reply (message);
|
||||||
|
blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
|
||||||
|
g_assert_no_error (local_error);
|
||||||
|
g_assert_nonnull (blob);
|
||||||
|
g_free (blob);
|
||||||
|
g_clear_object (&reply);
|
||||||
|
|
||||||
|
/* Error */
|
||||||
|
reply = g_dbus_message_new_method_error (message, "Error.Name", "Some error message");
|
||||||
|
blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
|
||||||
|
g_assert_no_error (local_error);
|
||||||
|
g_assert_nonnull (blob);
|
||||||
|
g_free (blob);
|
||||||
|
|
||||||
|
g_clear_object (&reply);
|
||||||
|
g_clear_object (&message);
|
||||||
|
|
||||||
|
/* Signal */
|
||||||
|
message = g_dbus_message_new_signal ("/the/path", "org.some.Interface", "SignalName");
|
||||||
|
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
|
||||||
|
g_assert_no_error (local_error);
|
||||||
|
g_assert_nonnull (blob);
|
||||||
|
g_free (blob);
|
||||||
|
g_clear_object (&message);
|
||||||
|
|
||||||
|
/* Also check that an unknown message type is allowed */
|
||||||
|
message = g_dbus_message_new ();
|
||||||
|
g_dbus_message_set_message_type (message, 123);
|
||||||
|
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
|
||||||
|
g_assert_no_error (local_error);
|
||||||
|
g_assert_nonnull (blob);
|
||||||
|
g_free (blob);
|
||||||
|
g_clear_object (&message);
|
||||||
|
|
||||||
|
/* Even one with a well-defined field on it */
|
||||||
|
message = g_dbus_message_new ();
|
||||||
|
g_dbus_message_set_message_type (message, 123);
|
||||||
|
g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS, g_variant_new_uint32 (0));
|
||||||
|
blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
|
||||||
|
g_assert_no_error (local_error);
|
||||||
|
g_assert_nonnull (blob);
|
||||||
|
g_free (blob);
|
||||||
|
g_clear_object (&message);
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1755,6 +1906,8 @@ main (int argc,
|
|||||||
test_message_serialize_invalid);
|
test_message_serialize_invalid);
|
||||||
g_test_add_func ("/gdbus/message-serialize/header-checks",
|
g_test_add_func ("/gdbus/message-serialize/header-checks",
|
||||||
test_message_serialize_header_checks);
|
test_message_serialize_header_checks);
|
||||||
|
g_test_add_func ("/gdbus/message-serialize/header-checks/valid",
|
||||||
|
test_message_serialize_header_checks_valid);
|
||||||
g_test_add_func ("/gdbus/message-serialize/double-array",
|
g_test_add_func ("/gdbus/message-serialize/double-array",
|
||||||
test_message_serialize_double_array);
|
test_message_serialize_double_array);
|
||||||
g_test_add_func ("/gdbus/message-serialize/empty-structure",
|
g_test_add_func ("/gdbus/message-serialize/empty-structure",
|
||||||
|
Loading…
Reference in New Issue
Block a user