Skip to content

Commit 81536ab

Browse files
committed
libusb: fix one more race condition found by TSan
1 parent 6dfdebc commit 81536ab

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

patches/libusb-1.0.25.patch

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,3 +820,130 @@ index 14a0cd36..e940356f 100644
820820
--
821821
2.41.0
822822

823+
From e63455ac85ec8f7dda4b20dd639c270d69205344 Mon Sep 17 00:00:00 2001
824+
From: osy <[email protected]>
825+
Date: Mon, 25 Aug 2025 12:04:57 -0700
826+
Subject: [PATCH] darwin: fix race condition on device open
827+
828+
Similar to the previous commit with device capture counts, we also need to
829+
take account of multiple contexts calling open/close on a device and make
830+
sure the open_count is immune to data races.
831+
---
832+
libusb/os/darwin_usb.c | 39 ++++++++++++++++++++++++++++++++++-----
833+
libusb/os/darwin_usb.h | 1 +
834+
2 files changed, 35 insertions(+), 5 deletions(-)
835+
836+
diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
837+
index e940356f..58414a31 100644
838+
--- a/libusb/os/darwin_usb.c
839+
+++ b/libusb/os/darwin_usb.c
840+
@@ -190,6 +190,7 @@ static void darwin_deref_cached_device(struct darwin_cached_device *cached_dev)
841+
}
842+
IOObjectRelease (cached_dev->service);
843+
usbi_mutex_destroy (&cached_dev->capture_mutex);
844+
+ usbi_mutex_destroy (&cached_dev->open_mutex);
845+
free (cached_dev);
846+
}
847+
}
848+
@@ -1080,6 +1081,7 @@ static enum libusb_error darwin_get_cached_device(struct libusb_context *ctx, io
849+
850+
/* initialize locks */
851+
usbi_mutex_init (&new_device->capture_mutex);
852+
+ usbi_mutex_init (&new_device->open_mutex);
853+
}
854+
855+
/* keep track of devices regardless of if we successfully enumerate them to
856+
@@ -1243,7 +1245,8 @@ static enum libusb_error darwin_scan_devices(struct libusb_context *ctx) {
857+
return LIBUSB_SUCCESS;
858+
}
859+
860+
-static int darwin_open (struct libusb_device_handle *dev_handle) {
861+
+/* call holding open_mutex lock */
862+
+static int _darwin_open_locked (struct libusb_device_handle *dev_handle) {
863+
struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
864+
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
865+
IOReturn kresult;
866+
@@ -1292,7 +1295,18 @@ static int darwin_open (struct libusb_device_handle *dev_handle) {
867+
return 0;
868+
}
869+
870+
-static void darwin_close (struct libusb_device_handle *dev_handle) {
871+
+static int darwin_open (struct libusb_device_handle *dev_handle) {
872+
+ struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
873+
+ enum libusb_error ret;
874+
+
875+
+ usbi_mutex_lock (&dpriv->open_mutex);
876+
+ ret = _darwin_open_locked (dev_handle);
877+
+ usbi_mutex_unlock (&dpriv->open_mutex);
878+
+ return ret;
879+
+}
880+
+
881+
+/* call holding open_mutex lock */
882+
+static void _darwin_close_locked (struct libusb_device_handle *dev_handle) {
883+
struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
884+
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
885+
IOReturn kresult;
886+
@@ -1336,6 +1350,14 @@ static void darwin_close (struct libusb_device_handle *dev_handle) {
887+
}
888+
}
889+
890+
+static void darwin_close (struct libusb_device_handle *dev_handle) {
891+
+ struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
892+
+
893+
+ usbi_mutex_lock (&dpriv->open_mutex);
894+
+ _darwin_close_locked (dev_handle);
895+
+ usbi_mutex_unlock (&dpriv->open_mutex);
896+
+}
897+
+
898+
static int darwin_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config) {
899+
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
900+
901+
@@ -1710,11 +1732,15 @@ static int darwin_restore_state (struct libusb_device_handle *dev_handle, int8_t
902+
unsigned long claimed_interfaces) {
903+
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
904+
struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
905+
- int open_count = dpriv->open_count;
906+
+ int open_count;
907+
int ret;
908+
909+
struct libusb_context *ctx = HANDLE_CTX (dev_handle);
910+
911+
+ usbi_mutex_lock (&dpriv->open_mutex);
912+
+
913+
+ open_count = dpriv->open_count;
914+
+
915+
/* clear claimed interfaces temporarily */
916+
dev_handle->claimed_interfaces = 0;
917+
918+
@@ -1723,11 +1749,14 @@ static int darwin_restore_state (struct libusb_device_handle *dev_handle, int8_t
919+
dpriv->open_count = 1;
920+
921+
/* clean up open interfaces */
922+
- (void) darwin_close (dev_handle);
923+
+ (void) _darwin_close_locked (dev_handle);
924+
925+
/* re-open the device */
926+
- ret = darwin_open (dev_handle);
927+
+ ret = _darwin_open_locked (dev_handle);
928+
dpriv->open_count = open_count;
929+
+
930+
+ usbi_mutex_unlock (&dpriv->open_mutex);
931+
+
932+
if (LIBUSB_SUCCESS != ret) {
933+
/* could not restore configuration */
934+
return LIBUSB_ERROR_NOT_FOUND;
935+
diff --git a/libusb/os/darwin_usb.h b/libusb/os/darwin_usb.h
936+
index cde286e7..22f151c1 100644
937+
--- a/libusb/os/darwin_usb.h
938+
+++ b/libusb/os/darwin_usb.h
939+
@@ -191,6 +191,7 @@ struct darwin_cached_device {
940+
bool in_reenumerate;
941+
int capture_count;
942+
usbi_mutex_t capture_mutex;
943+
+ usbi_mutex_t open_mutex;
944+
};
945+
946+
struct darwin_device_priv {
947+
--
948+
2.41.0
949+

0 commit comments

Comments
 (0)