From be76bef5b716d27b78fba120d3f9b815ed3380b9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 21 Aug 2013 14:18:09 +0200 Subject: hotplug: Don't call the user callback while holding various locks Calling user callbacks with locks held is a bad idea and should be avoided whenever possible. Before this patch this could lead ie to the following hang: 1) User calls libusb_hotplug_register_callback with the LIBUSB_HOTPLUG_ENUMERATE flag 2) libusb_hotplug_register_callback calls the user callback while holding the hotplug_cbs_lock 3) The callback calls a synchronous libusb function 4) The synchronous libusb function calls libusb_handle_events 5) There is an hotplug event waiting in the hotplug pipe and libusb_handle_events calls usbi_hotplug_match 6) usbi_hotplug_match tries to take the lock a 2nd time 7) hang / assert / abort (depending on the platform) Signed-off-by: Hans de Goede --- libusb/hotplug.c | 24 +++++++++++++++++------- libusb/version_nano.h | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/libusb/hotplug.c b/libusb/hotplug.c index ec91162..16725f2 100644 --- a/libusb/hotplug.c +++ b/libusb/hotplug.c @@ -241,19 +241,29 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, list_add(&new_callback->list, &ctx->hotplug_cbs); - if (flags & LIBUSB_HOTPLUG_ENUMERATE) { - struct libusb_device *dev; + usbi_mutex_unlock(&ctx->hotplug_cbs_lock); + - usbi_mutex_lock(&ctx->usb_devs_lock); + if (flags & LIBUSB_HOTPLUG_ENUMERATE) { + int i, len; + struct libusb_device **devs; + + len = libusb_get_device_list(ctx, &devs); + if (len < 0) { + libusb_hotplug_deregister_callback(ctx, + new_callback->handle); + return len; + } - list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) { - (void) usbi_hotplug_match_cb (ctx, dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, new_callback); + for (i = 0; i < len; i++) { + usbi_hotplug_match_cb(ctx, devs[i], + LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, + new_callback); } - usbi_mutex_unlock(&ctx->usb_devs_lock); + libusb_free_device_list(devs, 1); } - usbi_mutex_unlock(&ctx->hotplug_cbs_lock); if (handle) { *handle = new_callback->handle; diff --git a/libusb/version_nano.h b/libusb/version_nano.h index acce2c9..4972515 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 10813 +#define LIBUSB_NANO 10814 -- cgit v1.2.1