@@ -947,3 +947,98 @@ index cde286e7..22f151c1 100644
947947- -
9489482.41.0
949949
950+ From 80a7d8ed3d6f3b6750432c1c87a74b2b1db03685 Mon Sep 17 00:00:00 2001
951+ 952+ Date: Wed, 1 Oct 2025 12:00:09 -0700
953+ Subject: [PATCH 1/2] darwin: handle error from GetConfigurationDescriptorPtr
954+
955+ When a device is disconnected or otherwise `dpriv->device` is invalid,
956+ `GetConfigurationDescriptorPtr` will return `kIOReturnNoDevice` and
957+ `IOUSBConfigurationDescriptorPtr` will not be set. This means that we
958+ have an uninitialized pointer that is read from which is... very bad.
959+ ---
960+ libusb/os/darwin_usb.c | 14 +++++++++-----
961+ 1 file changed, 9 insertions(+), 5 deletions(-)
962+
963+ diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
964+ index 58414a31..d385a0e8 100644
965+ --- a/libusb/os/darwin_usb.c
966+ +++ b/libusb/os/darwin_usb.c
967+ @@ -698,9 +698,9 @@ static int get_configuration_index (struct libusb_device *dev, UInt8 config_valu
968+ return darwin_to_libusb (kresult);
969+
970+ for (i = 0 ; i < numConfig ; i++) {
971+ - (*(priv->device))->GetConfigurationDescriptorPtr (priv->device, i, &desc);
972+ + kresult = (*(priv->device))->GetConfigurationDescriptorPtr (priv->device, i, &desc);
973+
974+ - if (desc->bConfigurationValue == config_value)
975+ + if (kresult == kIOReturnSuccess && desc->bConfigurationValue == config_value)
976+ return i;
977+ }
978+
979+ @@ -1823,7 +1823,11 @@ static int darwin_reenumerate_device (struct libusb_device_handle *dev_handle, b
980+ cached_configurations = alloca (sizeof (*cached_configurations) * descriptor.bNumConfigurations);
981+
982+ for (i = 0 ; i < descriptor.bNumConfigurations ; ++i) {
983+ - (*(dpriv->device))->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration);
984+ + kresult = (*(dpriv->device))->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration);
985+ + if (kresult != kIOReturnSuccess) {
986+ + dpriv->in_reenumerate = false;
987+ + return LIBUSB_ERROR_NOT_FOUND;
988+ + }
989+ memcpy (cached_configurations + i, cached_configuration, sizeof (cached_configurations[i]));
990+ }
991+
992+ @@ -1883,8 +1887,8 @@ static int darwin_reenumerate_device (struct libusb_device_handle *dev_handle, b
993+ }
994+
995+ for (i = 0 ; i < descriptor.bNumConfigurations ; ++i) {
996+ - (void) (*(dpriv->device))->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration);
997+ - if (memcmp (cached_configuration, cached_configurations + i, sizeof (cached_configurations[i]))) {
998+ + kresult = (*(dpriv->device))->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration);
999+ + if (kresult != kIOReturnSuccess || memcmp (cached_configuration, cached_configurations + i, sizeof (cached_configurations[i]))) {
1000+ usbi_dbg (ctx, "darwin/reenumerate_device: configuration descriptor %d changed", i);
1001+ return LIBUSB_ERROR_NOT_FOUND;
1002+ }
1003+ - -
1004+ 2.41.0
1005+
1006+ From 9eaebb714169264c346bcba0100ac650aba40002 Mon Sep 17 00:00:00 2001
1007+ 1008+ Date: Wed, 1 Oct 2025 12:17:02 -0700
1009+ Subject: [PATCH 2/2] darwin: do not set NULL device in darwin_reload_device
1010+
1011+ We need to maintain the invariant that `device` is never an invalid
1012+ pointer because another thread might be concurrently accessing it. We
1013+ want that thread to error from an outdated `device` rather than crash
1014+ on a NULL pointer.
1015+ ---
1016+ libusb/os/darwin_usb.c | 8 +++++---
1017+ 1 file changed, 5 insertions(+), 3 deletions(-)
1018+
1019+ diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
1020+ index d385a0e8..6407d7b6 100644
1021+ --- a/libusb/os/darwin_usb.c
1022+ +++ b/libusb/os/darwin_usb.c
1023+ @@ -2540,13 +2540,15 @@ static bool darwin_has_capture_entitlements (void) {
1024+ static int darwin_reload_device (struct libusb_device_handle *dev_handle) {
1025+ struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
1026+ enum libusb_error err;
1027+ + usb_device_t **new_device;
1028+
1029+ usbi_mutex_lock(&darwin_cached_devices_mutex);
1030+ - (*(dpriv->device))->Release(dpriv->device);
1031+ - dpriv->device = darwin_device_from_service (HANDLE_CTX (dev_handle), dpriv->service);
1032+ - if (!dpriv->device) {
1033+ + new_device = darwin_device_from_service (HANDLE_CTX (dev_handle), dpriv->service);
1034+ + if (!new_device) {
1035+ err = LIBUSB_ERROR_NO_DEVICE;
1036+ } else {
1037+ + (*(dpriv->device))->Release(dpriv->device);
1038+ + dpriv->device = new_device;
1039+ err = LIBUSB_SUCCESS;
1040+ }
1041+ usbi_mutex_unlock(&darwin_cached_devices_mutex);
1042+ - -
1043+ 2.41.0
1044+
0 commit comments