location: validate SUPL host as FQDN or IP

When parsing a SUPL address, if the host is not a valid IPv4 address,
validate it as a FQDN (allowing only alphanumeric characters, dots,
and hyphens). This prevents injecting AT command delimiters (like CR
or semicolon) into the host string, which is later spliced into
modem-specific AT commands (+XLCSSLP).

Introduce a common helper mm_utils_is_valid_fqdn() to validate FQDNs,
and add unit tests for it.

https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/work_items/1063

Signed-off-by: Aleksander Morgado <aleksandermj@google.com>
This commit is contained in:
Aleksander Morgado
2026-07-10 13:43:48 +02:00
committed by Aleksander Morgado
parent 1ee3a443b1
commit a39d46c637
3 changed files with 39 additions and 0 deletions
+20
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)
@@ -5957,3 +5962,18 @@ mm_utils_remove_control_characters (gchar *str)
}
*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;
}
+1
View File
@@ -572,6 +572,7 @@ gboolean mm_parse_supl_address (const gchar *supl,
GError **error);
void mm_utils_remove_control_characters (gchar *str);
gboolean mm_utils_is_valid_fqdn (const gchar *fqdn);
gboolean mm_validate_cbs_channels (GArray *channels,
GError **error);
+18
View File
@@ -4891,6 +4891,23 @@ test_remove_control_characters (void *f, gpointer d)
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"));
}
/*****************************************************************************/
typedef struct {
@@ -5438,6 +5455,7 @@ int main (int argc, char **argv)
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_cpol_response, NULL));