diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2017-03-30 21:14:46 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2017-03-30 21:36:33 +0200 |
commit | 822bfa4ca163ef17a0fc60d03bfae462091885bf (patch) | |
tree | a2979a6ff0c986b19e6aef1f144244d007aeef7a /src/mm-base-manager.c | |
parent | 27e4c74c6007ceac5611f2fc4e314217ebf8d25a (diff) |
base-manager: fix segfault when using already disposed MMDevice
Since commit e9d0989ed069, the MMDevice may be removed from the
tracking hash table when the support check operation fails to create a
modem object.
If this failure happens due to the port probe cancellations requested
during the udev removal event for a given device port, we would end up
using an already disposed object and triggering a segfault.
This fix just makes sure a full valid reference to the MMDevice object
is kept around until we're done using it.
[mm-base-manager.c:216] device_removed(): (usbmisc/cdc-wdm1): released by device '/sys/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1.4'
[mm-plugin-manager.c:1131] device_context_port_released(): [plugin manager] task 5: port released: cdc-wdm1
[mm-base-manager.c:216] device_removed(): (tty/ttyACM0): released by device '/sys/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1.4'
[mm-plugin-manager.c:1131] device_context_port_released(): [plugin manager] task 5: port released: ttyACM0
[mm-base-manager.c:221] device_removed(): Removing empty device '/sys/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1.4'
[mm-plugin-manager.c:1219] device_context_cancel(): [plugin manager) task 5: cancellation requested
[mm-plugin-manager.c:979] device_context_continue(): [plugin manager] task 5: no more ports to probe
[mm-plugin-manager.c:813] device_context_complete(): [plugin manager] task 5: finished in '0.090510' seconds
[mm-base-manager.c:172] device_support_check_ready(): Couldn't check support for device '/sys/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1.4': Operation was cancelled
[mm-base-manager.c:223] device_removed(): Device support check has been cancelled
Thread 1 "ModemManager" received signal SIGSEGV, Segmentation fault.
0x00007ffff6543c50 in g_str_hash () from /usr/lib/libglib-2.0.so.0
(gdb) bt
#0 0x00007ffff6543c50 in g_str_hash () at /usr/lib/libglib-2.0.so.0
#1 0x00007ffff6542b2d in () at /usr/lib/libglib-2.0.so.0
#2 0x0000000000439675 in device_removed (self=0x770900, kernel_device=0x763e60) at mm-base-manager.c:225
#3 0x0000000000439e70 in handle_uevent (client=0x769c20, action=0x81d910 "remove", device=0x7fffe4001c40, user_data=0x770900) at mm-base-manager.c:415
#4 0x00007ffff54c61c8 in ffi_call_unix64 () at /usr/lib/libffi.so.6
#5 0x00007ffff54c5c2a in ffi_call () at /usr/lib/libffi.so.6
#6 0x00007ffff682d7ae in g_cclosure_marshal_generic ()
at /usr/lib/libgobject-2.0.so.0
#7 0x00007ffff682cf75 in g_closure_invoke () at /usr/lib/libgobject-2.0.so.0
#8 0x00007ffff683ef82 in () at /usr/lib/libgobject-2.0.so.0
#9 0x00007ffff6847bcc in g_signal_emit_valist ()
at /usr/lib/libgobject-2.0.so.0
#10 0x00007ffff6847faf in g_signal_emit () at /usr/lib/libgobject-2.0.so.0
#11 0x00007ffff7023c74 in () at /usr/lib/libgudev-1.0.so.0
#12 0x00007ffff655445a in g_main_context_dispatch ()
at /usr/lib/libglib-2.0.so.0
#13 0x00007ffff6554810 in () at /usr/lib/libglib-2.0.so.0
#14 0x00007ffff6554b32 in g_main_loop_run () at /usr/lib/libglib-2.0.so.0
#15 0x0000000000437bf5 in main (argc=2, argv=0x7fffffffeb28) at
main.c:180
(gdb) fr 2
#2 0x0000000000439675 in device_removed (self=0x770900, kernel_device=0x763e60) at mm-base-manager.c:225
225 g_hash_table_remove (self->priv->devices, mm_device_get_uid (device));
(gdb) p mm_device_get_uid (device)
$1 = (const gchar *) 0x0
(gdb) p *device
$3 = {parent = {g_type_instance = {g_class = 0x0}, ref_count = 0, qdata = 0x0}, priv = 0x7feb20}
Diffstat (limited to 'src/mm-base-manager.c')
-rw-r--r-- | src/mm-base-manager.c | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c index e662d9fb..58cea119 100644 --- a/src/mm-base-manager.c +++ b/src/mm-base-manager.c @@ -218,11 +218,22 @@ device_removed (MMBaseManager *self, /* If port probe list gets empty, remove the device object iself */ if (!mm_device_peek_port_probe_list (device)) { + /* The callback triggered when the device support is cancelled may end up + * removing the device from the HT, and that was the last full reference + * we kept. So, in order to make sure the reference is still valid after + * support_check_cancel(), we hold a full reference ourselves. */ mm_dbg ("Removing empty device '%s'", mm_device_get_uid (device)); - if (mm_plugin_manager_device_support_check_cancel (self->priv->plugin_manager, device)) - mm_dbg ("Device support check has been cancelled"); - mm_device_remove_modem (device); - g_hash_table_remove (self->priv->devices, mm_device_get_uid (device)); + g_object_ref (device); + { + if (mm_plugin_manager_device_support_check_cancel (self->priv->plugin_manager, device)) + mm_dbg ("Device support check has been cancelled"); + + /* The device may have already been removed from the tracking HT, we + * just try to remove it and if it fails, we ignore it */ + mm_device_remove_modem (device); + g_hash_table_remove (self->priv->devices, mm_device_get_uid (device)); + } + g_object_unref (device); } } |