summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksandermj@chromium.org>2022-12-16 22:16:06 +0000
committerAleksander Morgado <aleksandermj@chromium.org>2022-12-30 13:26:39 +0000
commit1198bdba33a6659b7bb57b612601f3fde45bac0d (patch)
treebd9caf8c73264ecab31181e7d9b08eab18d636e7
parent6d08c3dfa6954a632684fd5639943f27bbaaa7c0 (diff)
downloadModemManager-1198bdba33a6659b7bb57b612601f3fde45bac0d.tar.gz
base-modem: don't assume ports tables always exist
The 'link_ports' and 'ports' tables are created during object init(), but they are fully removed and cleared during dispose(). Given that the MMDevice executes an explicit g_object_run_dispose(), there may be cases where a long-running operation that isn't cancelled ends up being completed by the time the object disposal has already run at least once. That would end up crashing the process if we attempt to e.g. iterate over one of the ports hash tables: 0x00007c3594eb3b93 (libglib-2.0.so.0 - ghash.c: 1180) g_hash_table_iter_next 0x00005b60d86f2563 (ModemManager - mm-base-modem.c: 1133) mm_base_modem_get_port_infos 0x00005b60d870228e (ModemManager - mm-iface-modem.c: 4013) fcc_unlock 0x00007c35950126a8 (libgio-2.0.so.0 - gtask.c: 1230) g_task_return_now 0x00007c35950116fa (libgio-2.0.so.0 - gtask.c: 1300) g_task_return 0x00007c3595011d12 (libgio-2.0.so.0 - gtask.c: 1930) g_task_return_new_error 0x00005b60d87518f2 (ModemManager - mm-broadband-modem-mbim.c: 1970) radio_state_set_up_ready 0x00007c35950126a8 (libgio-2.0.so.0 - gtask.c: 1230) g_task_return_now 0x00007c35950116fa (libgio-2.0.so.0 - gtask.c: 1300) g_task_return 0x00007c35950c486c (libmbim-glib.so.4 - mbim-device.c: 253) transaction_task_complete_and_free 0x00007c35950c714b (libmbim-glib.so.4 - mbim-device.c: 335) transaction_timed_out 0x00007c3594ec1232 (libglib-2.0.so.0 - gmain.c: 4971) g_timeout_dispatch 0x00007c3594ec43fc (libglib-2.0.so.0 - gmain.c: 3417) g_main_context_dispatch 0x00007c3594ec4704 (libglib-2.0.so.0 - gmain.c: 4211) g_main_context_iterate 0x00007c3594ec4978 (libglib-2.0.so.0 - gmain.c: 4411) g_main_loop_run 0x00005b60d86d7c56 (ModemManager - main.c: 217) main 0x00007c3594c526c5 (libc.so.6 + 0x000286c5) __libc_init_first 0x00007c3594c52781 (libc.so.6 + 0x00028781) __libc_start_main 0x00005b60d86d7970 (ModemManager + 0x00061970) _start Fixes https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/677 Change-Id: I6695c284f86a196e60de7f714bc1671332d08848 (cherry picked from commit a5058eb7991fec517f378d27adc5a409deeda1f0)
-rw-r--r--src/mm-base-modem.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c
index 13b6589bc..73780040d 100644
--- a/src/mm-base-modem.c
+++ b/src/mm-base-modem.c
@@ -326,6 +326,12 @@ base_modem_internal_grab_port (MMBaseModem *self,
subsys = mm_kernel_device_get_subsystem (kernel_device);
name = mm_kernel_device_get_name (kernel_device);
+ if (!self->priv->ports || (link_port && !self->priv->link_ports)) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Cannot add port '%s/%s', no ports table", subsys, name);
+ return NULL;
+ }
+
/* Check whether we already have it stored */
key = g_strdup_printf ("%s%s", subsys, name);
port = g_hash_table_lookup (self->priv->ports, key);
@@ -506,6 +512,12 @@ mm_base_modem_release_link_port (MMBaseModem *self,
g_autofree gchar *key = NULL;
MMPort *port;
+ if (!self->priv->link_ports) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Cannot release link port '%s/%s', no link ports table", subsystem, name);
+ return FALSE;
+ }
+
key = g_strdup_printf ("%s%s", subsystem, name);
port = g_hash_table_lookup (self->priv->link_ports, key);
if (!port) {
@@ -626,6 +638,13 @@ mm_base_modem_wait_link_port (MMBaseModem *self,
return;
}
+ if (!self->priv->link_ports) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Cannot wait for port '%s/%s', no link ports table", subsystem, name);
+ g_object_unref (task);
+ return;
+ }
+
key = g_strdup_printf ("%s%s", subsystem, name);
port = g_hash_table_lookup (self->priv->link_ports, key);
if (port) {
@@ -1101,6 +1120,9 @@ mm_base_modem_has_at_port (MMBaseModem *self)
gpointer value;
gpointer key;
+ if (!self->priv->ports)
+ return FALSE;
+
/* We'll iterate the ht of ports, looking for any port which is AT */
g_hash_table_iter_init (&iter, self->priv->ports);
while (g_hash_table_iter_next (&iter, &key, &value)) {
@@ -1127,6 +1149,11 @@ mm_base_modem_get_port_infos (MMBaseModem *self,
GArray *port_infos;
MMPort *port;
+ if (!self->priv->ports) {
+ *n_port_infos = 0;
+ return NULL;
+ }
+
*n_port_infos = g_hash_table_size (self->priv->ports);
port_infos = g_array_sized_new (FALSE, FALSE, sizeof (MMModemPortInfo), *n_port_infos);
g_hash_table_iter_init (&iter, self->priv->ports);
@@ -1321,6 +1348,14 @@ mm_base_modem_organize_ports (MMBaseModem *self,
if (self->priv->primary)
return TRUE;
+ /* Ports table is created on init and removed on dispose(), not on
+ * finalize(), so there is a chance this may happen */
+ if (!self->priv->ports) {
+ g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "No ports table");
+ return FALSE;
+ }
+
g_hash_table_iter_init (&iter, self->priv->ports);
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &candidate)) {
switch (mm_port_get_port_type (candidate)) {