From 4b70ea669d04f5bf8eb65fbb16f5763ae0e41c56 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Fri, 23 Sep 2022 13:41:53 +0000 Subject: libmbim-glib,message: new method to validate messages --- src/libmbim-glib/mbim-errors.h | 18 +- src/libmbim-glib/mbim-message.c | 132 +++++++++++++- src/libmbim-glib/mbim-message.h | 24 ++- src/libmbim-glib/test/test-message-builder.c | 60 +++++++ src/libmbim-glib/test/test-message-parser.c | 105 +++++++++++ src/libmbim-glib/test/test-message.c | 260 ++++++++++++++++++++++----- 6 files changed, 546 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/libmbim-glib/mbim-errors.h b/src/libmbim-glib/mbim-errors.h index 0769eba..19e1793 100644 --- a/src/libmbim-glib/mbim-errors.h +++ b/src/libmbim-glib/mbim-errors.h @@ -37,20 +37,22 @@ * @MBIM_CORE_ERROR_UNSUPPORTED: Not supported. * @MBIM_CORE_ERROR_ABORTED: Operation aborted. * @MBIM_CORE_ERROR_UNKNOWN_STATE: State is unknown. Since 1.16. + * @MBIM_CORE_ERROR_INCOMPLETE_MESSAGE: MBIM message is incomplete. Since 1.28. * * Common errors that may be reported by libmbim-glib. * * Since: 1.0 */ typedef enum { /*< since=1.0 >*/ - MBIM_CORE_ERROR_FAILED = 0, /*< nick=Failed >*/ - MBIM_CORE_ERROR_WRONG_STATE = 1, /*< nick=WrongState >*/ - MBIM_CORE_ERROR_TIMEOUT = 2, /*< nick=Timeout >*/ - MBIM_CORE_ERROR_INVALID_ARGS = 3, /*< nick=InvalidArgs >*/ - MBIM_CORE_ERROR_INVALID_MESSAGE = 4, /*< nick=InvalidMessage >*/ - MBIM_CORE_ERROR_UNSUPPORTED = 5, /*< nick=Unsupported >*/ - MBIM_CORE_ERROR_ABORTED = 6, /*< nick=Aborted >*/ - MBIM_CORE_ERROR_UNKNOWN_STATE = 7 /*< nick=UnknownState >*/ + MBIM_CORE_ERROR_FAILED = 0, /*< nick=Failed >*/ + MBIM_CORE_ERROR_WRONG_STATE = 1, /*< nick=WrongState >*/ + MBIM_CORE_ERROR_TIMEOUT = 2, /*< nick=Timeout >*/ + MBIM_CORE_ERROR_INVALID_ARGS = 3, /*< nick=InvalidArgs >*/ + MBIM_CORE_ERROR_INVALID_MESSAGE = 4, /*< nick=InvalidMessage >*/ + MBIM_CORE_ERROR_UNSUPPORTED = 5, /*< nick=Unsupported >*/ + MBIM_CORE_ERROR_ABORTED = 6, /*< nick=Aborted >*/ + MBIM_CORE_ERROR_UNKNOWN_STATE = 7, /*< nick=UnknownState >*/ + MBIM_CORE_ERROR_INCOMPLETE_MESSAGE = 8, /*< nick=IncompleteMessage >*/ } MbimCoreError; /** diff --git a/src/libmbim-glib/mbim-message.c b/src/libmbim-glib/mbim-message.c index 69de3a1..9de3ea8 100644 --- a/src/libmbim-glib/mbim-message.c +++ b/src/libmbim-glib/mbim-message.c @@ -3,7 +3,8 @@ /* * libmbim-glib -- GLib/GIO based library to control MBIM devices * - * Copyright (C) 2013 - 2018 Aleksander Morgado + * Copyright (C) 2013 - 2022 Aleksander Morgado + * Copyright (C) 2022 Google, Inc. */ #include @@ -119,6 +120,135 @@ _mbim_message_allocate (MbimMessageType message_type, return self; } +/*****************************************************************************/ + +static gboolean +_mbim_message_validate_generic_header (const MbimMessage *self, + GError **error) +{ + /* Validate that the generic header can be read before reading the message + * type and length */ + if (self->len < sizeof (struct header)) { + g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INCOMPLETE_MESSAGE, + "Message is shorter than the minimum header (%u < %u)", + self->len, (guint) sizeof (struct header)); + return FALSE; + } + + /* Validate that the size reported in the message header is available */ + if (self->len < MBIM_MESSAGE_GET_MESSAGE_LENGTH (self)) { + g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INCOMPLETE_MESSAGE, + "Message is incomplete (%u < %u)", + self->len, MBIM_MESSAGE_GET_MESSAGE_LENGTH (self)); + return FALSE; + } + + return TRUE; +} + +static gboolean +_mbim_message_validate_type_header (const MbimMessage *self, + GError **error) +{ + gsize message_header_size = 0; + + if (!_mbim_message_validate_generic_header (self, error)) + return FALSE; + + /* Validate message type and get additional minimum required size based on + * message type */ + switch (MBIM_MESSAGE_GET_MESSAGE_TYPE (self)) { + case MBIM_MESSAGE_TYPE_OPEN: + message_header_size = sizeof (struct header) + sizeof (struct open_message); + break; + case MBIM_MESSAGE_TYPE_CLOSE: + /* ignore check */ + break; + case MBIM_MESSAGE_TYPE_COMMAND: + message_header_size = sizeof (struct header) + sizeof (struct command_message); + break; + case MBIM_MESSAGE_TYPE_OPEN_DONE: + message_header_size = sizeof (struct header) + sizeof (struct open_done_message); + break; + case MBIM_MESSAGE_TYPE_CLOSE_DONE: + message_header_size = sizeof (struct header) + sizeof (struct close_done_message); + break; + case MBIM_MESSAGE_TYPE_COMMAND_DONE: + message_header_size = sizeof (struct header) + sizeof (struct command_done_message); + break; + case MBIM_MESSAGE_TYPE_FUNCTION_ERROR: + case MBIM_MESSAGE_TYPE_HOST_ERROR: + message_header_size = sizeof (struct header) + sizeof (struct error_message); + break; + case MBIM_MESSAGE_TYPE_INDICATE_STATUS: + message_header_size = sizeof (struct header) + sizeof (struct indicate_status_message); + break; + default: + case MBIM_MESSAGE_TYPE_INVALID: + g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_MESSAGE, + "Message type unknown: 0x%08x", MBIM_MESSAGE_GET_MESSAGE_TYPE (self)); + return FALSE; + } + + /* Validate that the message type specific header can be read. */ + if (message_header_size && (MBIM_MESSAGE_GET_MESSAGE_LENGTH (self) < message_header_size)) { + g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_MESSAGE, + "Invalid message size: message type header incomplete"); + return FALSE; + } + + return TRUE; +} + +gboolean +mbim_message_validate (const MbimMessage *self, + GError **error) +{ + gsize message_size = 0; + + if (!_mbim_message_validate_type_header (self, error)) + return FALSE; + + /* Get information buffer size */ + switch (MBIM_MESSAGE_GET_MESSAGE_TYPE (self)) { + case MBIM_MESSAGE_TYPE_COMMAND: + message_size = sizeof (struct header) + sizeof (struct command_message) + + GUINT32_FROM_LE (((struct full_message *)(self->data))->message.command.buffer_length); + break; + case MBIM_MESSAGE_TYPE_COMMAND_DONE: + message_size = sizeof (struct header) + sizeof (struct command_done_message) + + GUINT32_FROM_LE (((struct full_message *)(self->data))->message.command_done.buffer_length); + break; + case MBIM_MESSAGE_TYPE_INDICATE_STATUS: + message_size = sizeof (struct header) + sizeof (struct indicate_status_message) + + GUINT32_FROM_LE (((struct full_message *)(self->data))->message.indicate_status.buffer_length); + break; + case MBIM_MESSAGE_TYPE_OPEN: + case MBIM_MESSAGE_TYPE_CLOSE: + case MBIM_MESSAGE_TYPE_HOST_ERROR: + case MBIM_MESSAGE_TYPE_OPEN_DONE: + case MBIM_MESSAGE_TYPE_CLOSE_DONE: + case MBIM_MESSAGE_TYPE_FUNCTION_ERROR: + /* ignore check */ + break; + case MBIM_MESSAGE_TYPE_INVALID: + default: + g_assert_not_reached (); + break; + } + + /* The information buffer must fit within the message contents */ + if (message_size && (MBIM_MESSAGE_GET_MESSAGE_LENGTH (self) < message_size)) { + g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_MESSAGE, + "Invalid message size: information buffer incomplete"); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + static guint32 _mbim_message_get_information_buffer_offset (const MbimMessage *self) { diff --git a/src/libmbim-glib/mbim-message.h b/src/libmbim-glib/mbim-message.h index 86bd9b0..7485e22 100644 --- a/src/libmbim-glib/mbim-message.h +++ b/src/libmbim-glib/mbim-message.h @@ -3,7 +3,8 @@ /* * libmbim-glib -- GLib/GIO based library to control MBIM devices * - * Copyright (C) 2013 - 2014 Aleksander Morgado + * Copyright (C) 2013 - 2022 Aleksander Morgado + * Copyright (C) 2022 Google, Inc. */ #ifndef _LIBMBIM_GLIB_MBIM_MESSAGE_H_ @@ -273,6 +274,27 @@ guint32 mbim_message_get_transaction_id (const MbimMessage *self); void mbim_message_set_transaction_id (MbimMessage *self, guint32 transaction_id); +/** + * mbim_message_validate: + * @self: a #MbimMessage. + * @error: return location for error or %NULL. + * + * Validates the contents of the headers in the MBIM message. + * + * This operation may be used to ensure that the message is full and of a valid + * type. + * + * This operation does not validate that the specific contents of a given + * message type are available, that is done by the methods retrieving those + * specific contents. + * + * Returns: %TRUE if the message is valid, %FALSE if @error is set. + * + * Since: 1.28 + */ +gboolean mbim_message_validate (const MbimMessage *self, + GError **error); + G_DEFINE_AUTOPTR_CLEANUP_FUNC (MbimMessage, mbim_message_unref) /*****************************************************************************/ diff --git a/src/libmbim-glib/test/test-message-builder.c b/src/libmbim-glib/test/test-message-builder.c index df50bc1..ad16abd 100644 --- a/src/libmbim-glib/test/test-message-builder.c +++ b/src/libmbim-glib/test/test-message-builder.c @@ -78,6 +78,7 @@ test_message_printable (MbimMessage *message, static void test_basic_connect_pin_set_raw (void) { + GError *error = NULL; MbimMessage *message; MbimMessageCommandBuilder *builder; const guint8 expected_message [] = { @@ -119,6 +120,8 @@ test_basic_connect_pin_set_raw (void) message = _mbim_message_command_builder_complete (builder); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); test_message_trace ((const guint8 *)((GByteArray *)message)->data, ((GByteArray *)message)->len, @@ -181,6 +184,9 @@ test_basic_connect_pin_set (void) &error); g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -207,6 +213,7 @@ test_basic_connect_pin_set (void) static void test_basic_connect_connect_set_raw (void) { + GError *error = NULL; MbimMessage *message; MbimMessageCommandBuilder *builder; const guint8 expected_message [] = { @@ -265,6 +272,8 @@ test_basic_connect_connect_set_raw (void) message = _mbim_message_command_builder_complete (builder); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); test_message_trace ((const guint8 *)((GByteArray *)message)->data, ((GByteArray *)message)->len, @@ -345,6 +354,9 @@ test_basic_connect_connect_set (void) &error)); g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -404,6 +416,9 @@ test_basic_connect_service_activation_set (void) &error)); g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -496,6 +511,9 @@ test_basic_connect_device_service_subscribe_list_set (void) g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -568,6 +586,9 @@ test_ussd_set (void) g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -650,6 +671,9 @@ test_auth_akap_query (void) g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -723,6 +747,9 @@ test_stk_pac_set (void) g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -796,6 +823,9 @@ test_stk_terminal_response_set (void) g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -874,6 +904,9 @@ test_stk_envelope_set (void) g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -928,6 +961,9 @@ test_basic_connect_ip_packet_filters_set_none (void) g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -1015,6 +1051,9 @@ test_basic_connect_ip_packet_filters_set_one (void) g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -1131,6 +1170,9 @@ test_basic_connect_ip_packet_filters_set_two (void) g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -1203,6 +1245,9 @@ test_dss_connect_set (void) g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -1312,6 +1357,9 @@ test_basic_connect_multicarrier_providers_set (void) g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -1364,6 +1412,9 @@ test_ms_host_shutdown_notify_set (void) message = mbim_message_ms_host_shutdown_notify_set_new (&error); g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, @@ -1427,6 +1478,8 @@ test_ms_basic_connect_extensions_registration_parameters_set_0_unnamed_tlvs (voi &error)); g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); mbim_message_set_transaction_id (message, 1); @@ -1501,6 +1554,8 @@ test_ms_basic_connect_extensions_registration_parameters_set_1_unnamed_tlv (void &error)); g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); mbim_message_set_transaction_id (message, 1); @@ -1602,6 +1657,8 @@ test_ms_basic_connect_extensions_registration_parameters_set_3_unnamed_tlvs (voi &error)); g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); mbim_message_set_transaction_id (message, 1); @@ -1688,6 +1745,9 @@ test_ms_basic_connect_v3_connect_set (void) g_assert_no_error (error); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + mbim_message_set_transaction_id (message, 1); test_message_trace ((const guint8 *)((GByteArray *)message)->data, diff --git a/src/libmbim-glib/test/test-message-parser.c b/src/libmbim-glib/test/test-message-parser.c index 13e241c..93a4d51 100644 --- a/src/libmbim-glib/test/test-message-parser.c +++ b/src/libmbim-glib/test/test-message-parser.c @@ -135,6 +135,9 @@ test_basic_connect_visible_providers (void) 0x67, 0x00, 0x65, 0x00 }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_visible_providers_response_parse ( @@ -253,6 +256,9 @@ test_basic_connect_subscriber_ready_status (void) 0x31, 0x00, 0x32, 0x00 }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_subscriber_ready_status_response_parse ( @@ -349,6 +355,9 @@ test_basic_connect_device_caps (void) 0x4D, 0x00, 0x00, 0x00 }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_device_caps_response_parse ( @@ -449,6 +458,9 @@ test_basic_connect_ip_configuration (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_ip_configuration_response_parse ( @@ -600,6 +612,9 @@ test_basic_connect_ip_configuration_2 (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_ip_configuration_response_parse ( @@ -735,6 +750,9 @@ test_basic_connect_service_activation (void) 0x05, 0x06, 0x07, 0x08 }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_service_activation_response_parse ( @@ -801,6 +819,9 @@ test_basic_connect_register_state (void) 0x36, 0x00, 0x00, 0x00 }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_register_state_response_parse ( @@ -858,6 +879,9 @@ test_provisioned_contexts (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (!mbim_message_provisioned_contexts_response_parse ( @@ -901,6 +925,9 @@ test_sms_read_zero_pdu (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_sms_read_response_parse ( @@ -969,6 +996,9 @@ test_sms_read_single_pdu (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_sms_read_response_parse ( @@ -1066,6 +1096,9 @@ test_sms_read_multiple_pdu (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_sms_read_response_parse ( @@ -1163,6 +1196,9 @@ test_ussd (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_ussd_response_parse ( @@ -1260,6 +1296,9 @@ test_auth_akap (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_auth_akap_response_parse ( @@ -1349,6 +1388,9 @@ test_stk_pac_notification (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_stk_pac_notification_parse ( @@ -1527,6 +1569,9 @@ test_stk_pac_response (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + mbim_message_validate (response, &error); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_stk_pac_response_parse ( @@ -1584,6 +1629,9 @@ test_stk_terminal_response (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_stk_terminal_response_response_parse ( @@ -1650,6 +1698,9 @@ test_stk_envelope_response (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_stk_envelope_response_parse ( @@ -1696,6 +1747,9 @@ test_basic_connect_ip_packet_filters_none (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_ip_packet_filters_response_parse ( @@ -1761,6 +1815,9 @@ test_basic_connect_ip_packet_filters_one (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_ip_packet_filters_response_parse ( @@ -1860,6 +1917,9 @@ test_basic_connect_ip_packet_filters_two (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_ip_packet_filters_response_parse ( @@ -1933,6 +1993,9 @@ test_ms_firmware_id_get (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); g_assert (mbim_message_ms_firmware_id_get_response_parse ( @@ -1978,6 +2041,10 @@ test_basic_connect_connect_short (void) response = mbim_message_new (buffer, sizeof (buffer)); + /* generic validation passes because the MBIM message format is fine */ + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + /* should fail! */ g_assert (!mbim_message_connect_response_parse ( response, @@ -2055,6 +2122,8 @@ test_basic_connect_visible_providers_overflow (void) 0x67, 0x00, 0x65, 0x00 }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); result = mbim_message_visible_providers_response_parse (response, &n_providers, @@ -2153,6 +2222,9 @@ test_ms_basic_connect_extensions_base_stations (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); result = (mbim_message_ms_basic_connect_extensions_base_stations_info_response_parse ( @@ -2232,6 +2304,9 @@ test_ms_basic_connect_extensions_registration_parameters_0_unnamed_tlvs (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 3, 0); result = (mbim_message_ms_basic_connect_extensions_v3_registration_parameters_response_parse ( @@ -2301,6 +2376,9 @@ test_ms_basic_connect_extensions_registration_parameters_1_unnamed_tlv (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 3, 0); result = (mbim_message_ms_basic_connect_extensions_v3_registration_parameters_response_parse ( @@ -2400,6 +2478,9 @@ test_ms_basic_connect_extensions_registration_parameters_3_unnamed_tlvs (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 3, 0); result = (mbim_message_ms_basic_connect_extensions_v3_registration_parameters_response_parse ( @@ -2499,6 +2580,9 @@ test_ms_basic_connect_v3_connect_0_unnamed_tlvs (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 3, 0); result = (mbim_message_ms_basic_connect_v3_connect_response_parse ( @@ -2587,6 +2671,9 @@ test_ms_basic_connect_v3_connect_1_unnamed_tlv (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 3, 0); result = (mbim_message_ms_basic_connect_v3_connect_response_parse ( @@ -2705,6 +2792,9 @@ test_ms_basic_connect_v3_connect_3_unnamed_tlvs (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 3, 0); result = (mbim_message_ms_basic_connect_v3_connect_response_parse ( @@ -2816,6 +2906,9 @@ test_ms_basic_connect_extensions_device_caps_v3 (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 3, 0); result = (mbim_message_ms_basic_connect_extensions_v3_device_caps_response_parse ( @@ -2925,6 +3018,9 @@ test_ms_basic_connect_extensions_wake_reason_command (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 3, 0); result = (mbim_message_ms_basic_connect_extensions_v3_wake_reason_response_parse ( @@ -3004,6 +3100,9 @@ test_ms_basic_connect_extensions_wake_reason_command_payload (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 3, 0); result = (mbim_message_ms_basic_connect_extensions_v3_wake_reason_response_parse ( @@ -3088,6 +3187,9 @@ test_ms_basic_connect_extensions_wake_reason_packet (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 3, 0); result = (mbim_message_ms_basic_connect_extensions_v3_wake_reason_response_parse ( @@ -3182,6 +3284,9 @@ test_ms_uicc_low_level_access_application_list (void) }; response = mbim_message_new (buffer, sizeof (buffer)); + g_assert (mbim_message_validate (response, &error)); + g_assert_no_error (error); + test_message_printable (response, 1, 0); result = (mbim_message_ms_uicc_low_level_access_application_list_response_parse ( diff --git a/src/libmbim-glib/test/test-message.c b/src/libmbim-glib/test/test-message.c index 83edc59..e2216b6 100644 --- a/src/libmbim-glib/test/test-message.c +++ b/src/libmbim-glib/test/test-message.c @@ -9,15 +9,20 @@ #include "mbim-message.h" #include "mbim-cid.h" +#include "mbim-error-types.h" static void test_message_open (void) { MbimMessage *message; + GError *error = NULL; message = mbim_message_open_new (12345, 4096); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 12345); g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_OPEN); g_assert_cmpuint (mbim_message_get_message_length (message), ==, 16); @@ -29,13 +34,18 @@ test_message_open (void) static void test_message_open_done (void) { - MbimMessage *message; - const guint8 buffer [] = { 0x01, 0x00, 0x00, 0x80, - 0x10, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; + MbimMessage *message; + GError *error = NULL; + const guint8 buffer [] = { 0x01, 0x00, 0x00, 0x80, + 0x10, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; message = mbim_message_new (buffer, sizeof (buffer)); + g_assert (message != NULL); + + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1); g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_OPEN_DONE); @@ -49,10 +59,14 @@ static void test_message_close (void) { MbimMessage *message; + GError *error = NULL; message = mbim_message_close_new (12345); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 12345); g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_CLOSE); g_assert_cmpuint (mbim_message_get_message_length (message), ==, 12); @@ -63,13 +77,18 @@ test_message_close (void) static void test_message_close_done (void) { - MbimMessage *message; - const guint8 buffer [] = { 0x02, 0x00, 0x00, 0x80, - 0x10, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; + MbimMessage *message; + GError *error = NULL; + const guint8 buffer [] = { 0x02, 0x00, 0x00, 0x80, + 0x10, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; message = mbim_message_new (buffer, sizeof (buffer)); + g_assert (message != NULL); + + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1); g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_CLOSE_DONE); @@ -83,7 +102,8 @@ static void test_message_command_empty (void) { MbimMessage *message; - guint32 len; + GError *error = NULL; + guint32 len; message = mbim_message_command_new (12345, MBIM_SERVICE_BASIC_CONNECT, @@ -91,6 +111,9 @@ test_message_command_empty (void) MBIM_MESSAGE_COMMAND_TYPE_QUERY); g_assert (message != NULL); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 12345); g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND); g_assert_cmpuint (mbim_message_get_message_length (message), ==, 48); @@ -108,10 +131,11 @@ test_message_command_empty (void) static void test_message_command_not_empty (void) { - MbimMessage *message; + MbimMessage *message; const guint8 *buffer; - guint32 len; - const guint8 information_buffer [] = { + guint32 len; + GError *error = NULL; + const guint8 information_buffer [] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; @@ -123,6 +147,9 @@ test_message_command_not_empty (void) g_assert (message != NULL); mbim_message_command_append (message, information_buffer, sizeof (information_buffer)); + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 12345); g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND); g_assert_cmpuint (mbim_message_get_message_length (message), ==, 56); @@ -142,16 +169,17 @@ test_message_command_not_empty (void) static void test_message_command_custom_service (void) { - static const gchar *nick = "My custom service"; - static const MbimUuid uuid_custom = { + static const gchar *nick = "My custom service"; + static const MbimUuid uuid_custom = { .a = { 0x11, 0x22, 0x33, 0x44 }, .b = { 0x11, 0x11 }, .c = { 0x22, 0x22 }, .d = { 0x33, 0x33 }, .e = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; - guint service; + guint service; MbimMessage *message; + GError *error = NULL; service = mbim_register_custom_service (&uuid_custom, nick); g_assert (mbim_service_id_is_custom (service)); @@ -160,7 +188,11 @@ test_message_command_custom_service (void) service, 0x11223344, MBIM_MESSAGE_COMMAND_TYPE_QUERY); - g_assert (message); + g_assert (message != NULL); + + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + g_assert_cmpuint (mbim_message_command_get_service (message), ==, service); g_assert (mbim_uuid_cmp (mbim_message_command_get_service_id (message), &uuid_custom)); g_assert_cmpuint (mbim_message_command_get_cid (message), ==, 0x11223344); @@ -172,7 +204,55 @@ test_message_command_custom_service (void) static void test_message_command_done (void) { - MbimMessage *message; + MbimMessage *message; + GError *error = NULL; + const guint8 buffer [] = { 0x03, 0x00, 0x00, 0x80, + 0x3c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xa2, 0x89, 0xcc, 0x33, + 0xbc, 0xbb, 0x8b, 0x4f, + 0xb6, 0xb0, 0x13, 0x3e, + 0xc2, 0xaa, 0xe6, 0xdf, + 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + const guint8 expected_information_buffer [] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + const guint8 *out_information_buffer; + guint32 len; + + message = mbim_message_new (buffer, sizeof (buffer)); + g_assert (message != NULL); + + g_assert (mbim_message_validate (message, &error)); + g_assert_no_error (error); + + g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1); + g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND_DONE); + g_assert_cmpuint (mbim_message_get_message_length (message), ==, 60); + + g_assert_cmpuint (mbim_message_command_done_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT); + g_assert_cmpuint (mbim_message_command_done_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_PIN); + g_assert_cmpuint (mbim_message_command_done_get_status_code (message), ==, MBIM_STATUS_ERROR_NONE); + + out_information_buffer = mbim_message_command_done_get_raw_information_buffer (message, &len); + g_assert (buffer != NULL); + g_assert_cmpuint (len, ==, sizeof (expected_information_buffer)); + g_assert (memcmp (&expected_information_buffer, out_information_buffer, sizeof (expected_information_buffer)) == 0); + + mbim_message_unref (message); +} + +static void +test_message_command_done_short (void) +{ + gsize len; const guint8 buffer [] = { 0x03, 0x00, 0x00, 0x80, 0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -188,42 +268,136 @@ test_message_command_done (void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - const guint8 expected_information_buffer [] = { 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; - const guint8 *out_information_buffer; - guint32 len; + + /* If no full message received, always return INCOMPLETE_MESSAGE, which is + * the indication given to the reader in MbimDevice or MbimProxy to keep on + * reading without discarding the already read data. */ + for (len = 0; len < sizeof (buffer); len++) { + g_autoptr(MbimMessage) message = NULL; + g_autoptr(GError) error = NULL; + + message = mbim_message_new (buffer, len); + g_assert (message != NULL); + + g_assert (!mbim_message_validate (message, &error)); + g_assert_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INCOMPLETE_MESSAGE); + } +} + +static void +test_message_command_done_invalid_type_header (void) +{ + /* This message will be invalid because the size of the message must be at least + * 48 bytes for a command-done message type. */ + guint8 buffer [] = { + /* generic mbim header */ + 0x03, 0x00, 0x00, 0x80, /* type */ + 0x00, 0x00, 0x00, 0x00, /* length -- this will be modified in the test*/ + 0x01, 0x00, 0x00, 0x00, /* transaction id */ + /* fragment header */ + 0x01, 0x00, 0x00, 0x00, /* total */ + 0x00, 0x00, 0x00, 0x00, /* current */ + /* command done header */ + 0xa2, 0x89, 0xcc, 0x33, /* service id */ + 0xbc, 0xbb, 0x8b, 0x4f, + 0xb6, 0xb0, 0x13, 0x3e, + 0xc2, 0xaa, 0xe6, 0xdf, + 0x04, 0x00, 0x00, 0x00, /* command id */ + 0x00, 0x00, 0x00, 0x00, /* status code */ + 0x00, 0x00, 0x00, 0x00, /* buffer length */ + /* no buffer */ + }; + guint len; + + /* If no full message received, always return INCOMPLETE_MESSAGE, which is + * the indication given to the reader in MbimDevice or MbimProxy to keep on + * reading without discarding the already read data. */ + for (len = 12; len < sizeof (buffer); len++) { + g_autoptr(MbimMessage) message = NULL; + g_autoptr(GError) error = NULL; + + /* all our lengths are < 0xFF so we only have to modify 1 byte */ + buffer[4] = len; + + message = mbim_message_new (buffer, len); + g_assert (message != NULL); + + g_assert (!mbim_message_validate (message, &error)); + g_assert_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_MESSAGE); + } +} + +static void +test_message_command_done_invalid_buffer_length (void) +{ + g_autoptr(MbimMessage) message = NULL; + g_autoptr(GError) error = NULL; + + /* This message will be invalid because the buffer length would span out of the bounds + * imposed by the full message length */ + const guint8 buffer [] = { + /* generic mbim header */ + 0x03, 0x00, 0x00, 0x80, /* type */ + 0x30, 0x00, 0x00, 0x00, /* length 40 bytes, expects 0 bytes in the information buffer */ + 0x01, 0x00, 0x00, 0x00, /* transaction id */ + /* fragment header */ + 0x01, 0x00, 0x00, 0x00, /* total */ + 0x00, 0x00, 0x00, 0x00, /* current */ + /* command done header */ + 0xa2, 0x89, 0xcc, 0x33, /* service id */ + 0xbc, 0xbb, 0x8b, 0x4f, + 0xb6, 0xb0, 0x13, 0x3e, + 0xc2, 0xaa, 0xe6, 0xdf, + 0x04, 0x00, 0x00, 0x00, /* command id */ + 0x00, 0x00, 0x00, 0x00, /* status code */ + 0x04, 0x00, 0x00, 0x00, /* buffer length: 4 bytes, which is 4 more than expected */ + /* simple buffer buffer */ + 0x00, 0x00, 0x00, 0x00 + }; message = mbim_message_new (buffer, sizeof (buffer)); + g_assert (message != NULL); - g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1); - g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND_DONE); - g_assert_cmpuint (mbim_message_get_message_length (message), ==, 60); + g_assert (!mbim_message_validate (message, &error)); + g_assert_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_MESSAGE); +} - g_assert_cmpuint (mbim_message_command_done_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT); - g_assert_cmpuint (mbim_message_command_done_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_PIN); - g_assert_cmpuint (mbim_message_command_done_get_status_code (message), ==, MBIM_STATUS_ERROR_NONE); +static void +test_message_invalid_type (void) +{ + g_autoptr(MbimMessage) message = NULL; + g_autoptr(GError) error = NULL; + + const guint8 buffer [] = { + /* generic mbim header */ + 0x03, 0xAB, 0xCD, 0x80, /* unknown type */ + 0x0C, 0x00, 0x00, 0x00, /* length */ + 0x01, 0x00, 0x00, 0x00, /* transaction id */ + }; - out_information_buffer = mbim_message_command_done_get_raw_information_buffer (message, &len); - g_assert (buffer != NULL); - g_assert_cmpuint (len, ==, sizeof (expected_information_buffer)); - g_assert (memcmp (&expected_information_buffer, out_information_buffer, sizeof (expected_information_buffer)) == 0); + message = mbim_message_new (buffer, sizeof (buffer)); + g_assert (message != NULL); - mbim_message_unref (message); + g_assert (!mbim_message_validate (message, &error)); + g_assert_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_MESSAGE); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); - g_test_add_func ("/libmbim-glib/message/open", test_message_open); - g_test_add_func ("/libmbim-glib/message/open-done", test_message_open_done); - g_test_add_func ("/libmbim-glib/message/close", test_message_close); - g_test_add_func ("/libmbim-glib/message/close-done", test_message_close_done); - g_test_add_func ("/libmbim-glib/message/command/empty", test_message_command_empty); - g_test_add_func ("/libmbim-glib/message/command/not-empty", test_message_command_not_empty); - g_test_add_func ("/libmbim-glib/message/command/custom-service", test_message_command_custom_service); - g_test_add_func ("/libmbim-glib/message/command-done", test_message_command_done); + g_test_add_func ("/libmbim-glib/message/open", test_message_open); + g_test_add_func ("/libmbim-glib/message/open-done", test_message_open_done); + g_test_add_func ("/libmbim-glib/message/close", test_message_close); + g_test_add_func ("/libmbim-glib/message/close-done", test_message_close_done); + g_test_add_func ("/libmbim-glib/message/command/empty", test_message_command_empty); + g_test_add_func ("/libmbim-glib/message/command/not-empty", test_message_command_not_empty); + g_test_add_func ("/libmbim-glib/message/command/custom-service", test_message_command_custom_service); + g_test_add_func ("/libmbim-glib/message/command-done", test_message_command_done); + g_test_add_func ("/libmbim-glib/message/command-done/short", test_message_command_done_short); + g_test_add_func ("/libmbim-glib/message/command-done/invalid-type-header", test_message_command_done_invalid_type_header); + g_test_add_func ("/libmbim-glib/message/command-done/invalid-buffer-length", test_message_command_done_invalid_buffer_length); + g_test_add_func ("/libmbim-glib/message/invalid-type", test_message_invalid_type); return g_test_run (); } -- cgit v1.2.1