Merge request !1464 from 'aleksander/vreports'

Sanitize user inputs

https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1464
This commit is contained in:
Aleksander Morgado
2026-07-10 14:35:08 +02:00
8 changed files with 276 additions and 11 deletions
+7
View File
@@ -440,6 +440,13 @@ handle_deflect_auth_ready (MMAuthProvider *authp,
return;
}
/* Validate input number */
if (!mm_utils_is_valid_dial_number (ctx->number, &error)) {
mm_dbus_method_invocation_take_error (ctx->invocation, error);
handle_deflect_context_free (ctx);
return;
}
state = mm_gdbus_call_get_state (MM_GDBUS_CALL (ctx->self));
/* We can only deflect incoming call in ringing or waiting state */
+61 -1
View File
@@ -261,6 +261,13 @@ handle_change_pin_auth_ready (MMAuthProvider *authp,
return;
}
if (!mm_utils_is_numeric (ctx->old_pin) || !mm_utils_is_numeric (ctx->new_pin)) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"PIN must be numeric");
handle_change_pin_context_free (ctx);
return;
}
/* If changing PIN is not implemented, report an error */
if (!MM_BASE_SIM_GET_CLASS (ctx->self)->change_pin ||
!MM_BASE_SIM_GET_CLASS (ctx->self)->change_pin_finish) {
@@ -445,6 +452,13 @@ handle_enable_pin_auth_ready (MMAuthProvider *authp,
return;
}
if (!mm_utils_is_numeric (ctx->pin)) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"PIN must be numeric");
handle_enable_pin_context_free (ctx);
return;
}
/* If changing PIN is not implemented, report an error */
if (!MM_BASE_SIM_GET_CLASS (ctx->self)->enable_pin ||
!MM_BASE_SIM_GET_CLASS (ctx->self)->enable_pin_finish) {
@@ -869,6 +883,13 @@ handle_send_pin_auth_ready (MMAuthProvider *authp,
return;
}
if (!mm_utils_is_numeric (ctx->pin)) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"PIN must be numeric");
handle_send_pin_context_free (ctx);
return;
}
if (!mm_gdbus_sim_get_active (MM_GDBUS_SIM (ctx->self))) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Cannot send PIN: SIM not currently active");
@@ -974,6 +995,13 @@ handle_send_puk_auth_ready (MMAuthProvider *authp,
return;
}
if (!mm_utils_is_numeric (ctx->puk) || !mm_utils_is_numeric (ctx->new_pin)) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"PIN/PUK must be numeric");
handle_send_puk_context_free (ctx);
return;
}
if (!mm_gdbus_sim_get_active (MM_GDBUS_SIM (ctx->self))) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Cannot send PUK: SIM not currently active");
@@ -1518,12 +1546,34 @@ handle_set_preferred_networks_ready (MMBaseSim *self,
handle_set_preferred_networks_context_free (ctx);
}
static gboolean
validate_networks_list (GList *networks_list,
GError **error)
{
GList *l;
for (l = networks_list; l; l = g_list_next (l)) {
MMSimPreferredNetwork *network = (MMSimPreferredNetwork *)l->data;
const gchar *operator_code;
operator_code = mm_sim_preferred_network_get_operator_code (network);
if (!mm_utils_is_numeric (operator_code)) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"Invalid operator code: '%s'", operator_code);
return FALSE;
}
}
return TRUE;
}
static void
handle_set_preferred_networks_auth_ready (MMAuthProvider *authp,
GAsyncResult *res,
HandleSetPreferredNetworksContext *ctx)
{
GError *error = NULL;
GList *networks_list = NULL;
if (!mm_auth_provider_authorize_finish (authp, res, &error)) {
mm_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -1553,12 +1603,22 @@ handle_set_preferred_networks_auth_ready (MMAuthProvider *authp,
return;
}
networks_list = mm_sim_preferred_network_list_new_from_variant (ctx->networks);
if (!validate_networks_list (networks_list, &error)) {
g_list_free_full (networks_list, g_object_unref);
mm_dbus_method_invocation_take_error (ctx->invocation, error);
handle_set_preferred_networks_context_free (ctx);
return;
}
mm_obj_info (ctx->self, "processing user request to set preferred networks...");
MM_BASE_SIM_GET_CLASS (ctx->self)->set_preferred_networks (
ctx->self,
mm_sim_preferred_network_list_new_from_variant (ctx->networks),
networks_list,
(GAsyncReadyCallback)handle_set_preferred_networks_ready,
ctx);
g_list_free_full (networks_list, g_object_unref);
}
static gboolean
+6 -3
View File
@@ -6419,6 +6419,7 @@ modem_3gpp_ussd_context_send_unencoded (MMBroadbandModem *self)
{
Modem3gppUssdSendContext *ctx;
gchar *at_command = NULL;
gchar *quoted_command;
g_assert (self->priv->pending_ussd_action);
ctx = g_task_get_task_data (self->priv->pending_ussd_action);
@@ -6426,9 +6427,11 @@ modem_3gpp_ussd_context_send_unencoded (MMBroadbandModem *self)
/* Build AT command with action unencoded */
ctx->unencoded_used = TRUE;
ctx->current_is_unencoded = TRUE;
at_command = g_strdup_printf ("+CUSD=1,\"%s\",%d",
ctx->command,
MM_MODEM_GSM_USSD_SCHEME_7BIT);
quoted_command = mm_at_quote_string (ctx->command);
at_command = g_strdup_printf ("+CUSD=1,%s,%d",
quoted_command,
MM_MODEM_GSM_USSD_SCHEME_7BIT);
g_free (quoted_command);
mm_base_modem_at_command (MM_BASE_MODEM (self),
at_command,
+3 -7
View File
@@ -23,6 +23,7 @@
#include "mm-call-list.h"
#include "mm-error-helpers.h"
#include "mm-log-object.h"
#include "mm-modem-helpers.h"
#define CALL_LIST_POLLING_CONTEXT_TAG "voice-call-list-polling-context-tag"
#define IN_CALL_EVENT_CONTEXT_TAG "voice-in-call-event-context-tag"
@@ -176,14 +177,9 @@ create_outgoing_call_from_properties (MMIfaceModemVoice *self,
guint dtmf_tone_duration;
/* Don't create CALL from properties if either number is missing */
number = mm_call_properties_get_number (properties) ;
if (!number) {
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_INVALID_ARGS,
"Cannot create call: mandatory parameter 'number' is missing");
number = mm_call_properties_get_number (properties);
if (!mm_utils_is_valid_dial_number (number, error))
return NULL;
}
dtmf_tone_duration = mm_call_properties_get_dtmf_tone_duration (properties) ;
+78
View File
@@ -5554,6 +5554,11 @@ mm_parse_supl_address (const gchar *supl,
/* Try to parse first item as IP */
if (inet_pton (AF_INET, split[0], &ip) <= 0) {
/* Otherwise, assume it's a domain name */
if (!mm_utils_is_valid_fqdn (split[0])) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"Invalid SUPL host: not a valid FQDN or IP: %s", split[0]);
goto out;
}
if (out_fqdn)
*out_fqdn = g_strdup (split[0]);
if (out_ip)
@@ -5936,3 +5941,76 @@ mm_dtmf_split (const gchar *dtmf)
return array;
}
/*****************************************************************************/
void
mm_utils_remove_control_characters (gchar *str)
{
gchar *src = str;
gchar *dst = str;
if (!str)
return;
while (*src) {
if (((guint8)*src) >= 0x20) {
*dst = *src;
dst++;
}
src++;
}
*dst = '\0';
}
gboolean
mm_utils_is_valid_fqdn (const gchar *fqdn)
{
const gchar *c;
if (!fqdn || !fqdn[0])
return FALSE;
for (c = fqdn; *c; c++) {
if (!g_ascii_isalnum (*c) && *c != '-' && *c != '.')
return FALSE;
}
return TRUE;
}
gboolean
mm_utils_is_numeric (const gchar *str)
{
const gchar *c;
if (!str || !str[0])
return FALSE;
for (c = str; *c; c++) {
if (!g_ascii_isdigit (*c))
return FALSE;
}
return TRUE;
}
gboolean
mm_utils_is_valid_dial_number (const gchar *str,
GError **error)
{
const gchar *c;
if (!str || !str[0]) {
g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"missing number");
return FALSE;
}
for (c = str; *c; c++) {
if (((guint8)*c) < 0x20 || *c == ';') {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"invalid character '0x%02x' in number", (guint8)*c);
return FALSE;
}
}
return TRUE;
}
+6
View File
@@ -571,6 +571,12 @@ gboolean mm_parse_supl_address (const gchar *supl,
guint16 *out_port,
GError **error);
void mm_utils_remove_control_characters (gchar *str);
gboolean mm_utils_is_valid_fqdn (const gchar *fqdn);
gboolean mm_utils_is_numeric (const gchar *str);
gboolean mm_utils_is_valid_dial_number (const gchar *str,
GError **error);
gboolean mm_validate_cbs_channels (GArray *channels,
GError **error);
+3
View File
@@ -28,6 +28,7 @@
#include "mm-sms-part-3gpp.h"
#include "mm-charsets.h"
#include "mm-log.h"
#include "mm-modem-helpers.h"
#define PDU_SIZE 200
@@ -141,6 +142,8 @@ sms_decode_address (const guint8 *address,
unpacked = mm_charset_gsm_unpack (address, (len_digits * 4) / 7, 0, &unpacked_len);
unpacked_array = g_byte_array_new_take (unpacked, unpacked_len);
utf8 = mm_modem_charset_bytearray_to_utf8 (unpacked_array, MM_MODEM_CHARSET_GSM, FALSE, error);
if (utf8)
mm_utils_remove_control_characters (utf8);
} else if (addrtype == SMS_NUMBER_TYPE_INTL &&
addrplan == SMS_NUMBER_PLAN_TELEPHONE) {
/* International telphone number, format as "+1234567890" */
+112
View File
@@ -4872,6 +4872,114 @@ test_at_quote_string (void *f, gpointer d)
}
}
static void
test_remove_control_characters (void *f, gpointer d)
{
gchar str1[] = "hello\r\nworld";
gchar str2[] = "no_controls";
gchar str3[] = "\r\n\t";
mm_utils_remove_control_characters (str1);
g_assert_cmpstr (str1, ==, "helloworld");
mm_utils_remove_control_characters (str2);
g_assert_cmpstr (str2, ==, "no_controls");
mm_utils_remove_control_characters (str3);
g_assert_cmpstr (str3, ==, "");
mm_utils_remove_control_characters (NULL);
}
static void
test_is_valid_fqdn (void *f, gpointer d)
{
g_assert (mm_utils_is_valid_fqdn ("google.com"));
g_assert (mm_utils_is_valid_fqdn ("a.b.c.d"));
g_assert (mm_utils_is_valid_fqdn ("valid-host.com"));
g_assert (mm_utils_is_valid_fqdn ("123.com"));
g_assert (mm_utils_is_valid_fqdn ("a"));
g_assert (!mm_utils_is_valid_fqdn (NULL));
g_assert (!mm_utils_is_valid_fqdn (""));
g_assert (!mm_utils_is_valid_fqdn ("invalid host.com"));
g_assert (!mm_utils_is_valid_fqdn ("host;com"));
g_assert (!mm_utils_is_valid_fqdn ("host\rcom"));
g_assert (!mm_utils_is_valid_fqdn ("host/com"));
}
static void
test_is_numeric (void *f, gpointer d)
{
g_assert (mm_utils_is_numeric ("123456"));
g_assert (mm_utils_is_numeric ("0"));
g_assert (mm_utils_is_numeric ("0123456789"));
g_assert (!mm_utils_is_numeric (NULL));
g_assert (!mm_utils_is_numeric (""));
g_assert (!mm_utils_is_numeric ("123a45"));
g_assert (!mm_utils_is_numeric ("123 45"));
g_assert (!mm_utils_is_numeric ("123\r45"));
g_assert (!mm_utils_is_numeric ("+123"));
}
static void
test_is_valid_dial_number (void *f, gpointer d)
{
GError *error = NULL;
gboolean r;
r = mm_utils_is_valid_dial_number ("123456", &error);
g_assert (r);
g_assert_no_error (error);
r = mm_utils_is_valid_dial_number ("+123456", &error);
g_assert (r);
g_assert_no_error (error);
r = mm_utils_is_valid_dial_number ("*123#", &error);
g_assert (r);
g_assert_no_error (error);
r = mm_utils_is_valid_dial_number ("123,456", &error);
g_assert (r);
g_assert_no_error (error);
r = mm_utils_is_valid_dial_number ("123W456", &error);
g_assert (r);
g_assert_no_error (error);
r = mm_utils_is_valid_dial_number (NULL, &error);
g_assert (!r);
g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS);
g_clear_error (&error);
r = mm_utils_is_valid_dial_number ("", &error);
g_assert (!r);
g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS);
g_clear_error (&error);
r = mm_utils_is_valid_dial_number ("123;456", &error);
g_assert (!r);
g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS);
g_clear_error (&error);
r = mm_utils_is_valid_dial_number ("123\r456", &error);
g_assert (!r);
g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS);
g_clear_error (&error);
r = mm_utils_is_valid_dial_number ("123\n456", &error);
g_assert (!r);
g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS);
g_clear_error (&error);
r = mm_utils_is_valid_dial_number ("123\x01" "456", &error);
g_assert (!r);
g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS);
g_clear_error (&error);
}
/*****************************************************************************/
typedef struct {
@@ -5418,6 +5526,10 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_bcd_to_string, NULL));
g_test_suite_add (suite, TESTCASE (test_at_quote_string, NULL));
g_test_suite_add (suite, TESTCASE (test_remove_control_characters, NULL));
g_test_suite_add (suite, TESTCASE (test_is_valid_fqdn, NULL));
g_test_suite_add (suite, TESTCASE (test_is_numeric, NULL));
g_test_suite_add (suite, TESTCASE (test_is_valid_dial_number, NULL));
g_test_suite_add (suite, TESTCASE (test_cpol_response, NULL));