Skip to content

Commit e63455a

Browse files
committed
darwin: fix race condition on device open
Similar to the previous commit with device capture counts, we also need to take account of multiple contexts calling open/close on a device and make sure the open_count is immune to data races.
1 parent 26ba141 commit e63455a

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed

libusb/os/darwin_usb.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ static void darwin_deref_cached_device(struct darwin_cached_device *cached_dev)
190190
}
191191
IOObjectRelease (cached_dev->service);
192192
usbi_mutex_destroy (&cached_dev->capture_mutex);
193+
usbi_mutex_destroy (&cached_dev->open_mutex);
193194
free (cached_dev);
194195
}
195196
}
@@ -1080,6 +1081,7 @@ static enum libusb_error darwin_get_cached_device(struct libusb_context *ctx, io
10801081

10811082
/* initialize locks */
10821083
usbi_mutex_init (&new_device->capture_mutex);
1084+
usbi_mutex_init (&new_device->open_mutex);
10831085
}
10841086

10851087
/* keep track of devices regardless of if we successfully enumerate them to
@@ -1243,7 +1245,8 @@ static enum libusb_error darwin_scan_devices(struct libusb_context *ctx) {
12431245
return LIBUSB_SUCCESS;
12441246
}
12451247

1246-
static int darwin_open (struct libusb_device_handle *dev_handle) {
1248+
/* call holding open_mutex lock */
1249+
static int _darwin_open_locked (struct libusb_device_handle *dev_handle) {
12471250
struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
12481251
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
12491252
IOReturn kresult;
@@ -1292,7 +1295,18 @@ static int darwin_open (struct libusb_device_handle *dev_handle) {
12921295
return 0;
12931296
}
12941297

1295-
static void darwin_close (struct libusb_device_handle *dev_handle) {
1298+
static int darwin_open (struct libusb_device_handle *dev_handle) {
1299+
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
1300+
enum libusb_error ret;
1301+
1302+
usbi_mutex_lock (&dpriv->open_mutex);
1303+
ret = _darwin_open_locked (dev_handle);
1304+
usbi_mutex_unlock (&dpriv->open_mutex);
1305+
return ret;
1306+
}
1307+
1308+
/* call holding open_mutex lock */
1309+
static void _darwin_close_locked (struct libusb_device_handle *dev_handle) {
12961310
struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
12971311
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
12981312
IOReturn kresult;
@@ -1336,6 +1350,14 @@ static void darwin_close (struct libusb_device_handle *dev_handle) {
13361350
}
13371351
}
13381352

1353+
static void darwin_close (struct libusb_device_handle *dev_handle) {
1354+
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
1355+
1356+
usbi_mutex_lock (&dpriv->open_mutex);
1357+
_darwin_close_locked (dev_handle);
1358+
usbi_mutex_unlock (&dpriv->open_mutex);
1359+
}
1360+
13391361
static int darwin_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config) {
13401362
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
13411363

@@ -1710,11 +1732,15 @@ static int darwin_restore_state (struct libusb_device_handle *dev_handle, int8_t
17101732
unsigned long claimed_interfaces) {
17111733
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
17121734
struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
1713-
int open_count = dpriv->open_count;
1735+
int open_count;
17141736
int ret;
17151737

17161738
struct libusb_context *ctx = HANDLE_CTX (dev_handle);
17171739

1740+
usbi_mutex_lock (&dpriv->open_mutex);
1741+
1742+
open_count = dpriv->open_count;
1743+
17181744
/* clear claimed interfaces temporarily */
17191745
dev_handle->claimed_interfaces = 0;
17201746

@@ -1723,11 +1749,14 @@ static int darwin_restore_state (struct libusb_device_handle *dev_handle, int8_t
17231749
dpriv->open_count = 1;
17241750

17251751
/* clean up open interfaces */
1726-
(void) darwin_close (dev_handle);
1752+
(void) _darwin_close_locked (dev_handle);
17271753

17281754
/* re-open the device */
1729-
ret = darwin_open (dev_handle);
1755+
ret = _darwin_open_locked (dev_handle);
17301756
dpriv->open_count = open_count;
1757+
1758+
usbi_mutex_unlock (&dpriv->open_mutex);
1759+
17311760
if (LIBUSB_SUCCESS != ret) {
17321761
/* could not restore configuration */
17331762
return LIBUSB_ERROR_NOT_FOUND;

libusb/os/darwin_usb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ struct darwin_cached_device {
191191
bool in_reenumerate;
192192
int capture_count;
193193
usbi_mutex_t capture_mutex;
194+
usbi_mutex_t open_mutex;
194195
};
195196

196197
struct darwin_device_priv {

0 commit comments

Comments
 (0)