From 6a902c3b207a017cd699ac8bb6659abf32eb0c99 Mon Sep 17 00:00:00 2001 From: osy <50960678+osy@users.noreply.github.com> Date: Tue, 11 May 2021 20:58:59 -0700 Subject: [PATCH] darwin: add authorization for device capture To use USBDeviceReEnumerate with kUSBReEnumerateCaptureDeviceMask your app either needs to be running as root OR have the 'com.apple.vm.device-access' entitlement AND have the user authorization requested via IOServiceAuthorize(). We can use the capture re-enumerate APIs if either 1) the process is running as root or 2) the 'com.apple.vm.device-access' entitlement is used AND IOServiceAuthorize() is called. We assume that if the entitlement is not there then we are running as root--if this is not true, then darwin_detach_kernel_driver will fail anyways. The authorization status is cached in the device's start() so we have to stop() and start() the device by destroying the plugin and recreating it again. Signed-off-by: Nathan Hjelm --- Xcode/libusb.xcodeproj/project.pbxproj | 79 +++++++++++++++++++++++----------- configure.ac | 2 +- libusb/os/darwin_usb.c | 49 +++++++++++++++++++++ libusb/os/darwin_usb.h | 1 + libusb/version_nano.h | 2 +- 5 files changed, 106 insertions(+), 27 deletions(-) diff --git a/Xcode/libusb.xcodeproj/project.pbxproj b/Xcode/libusb.xcodeproj/project.pbxproj index fcda7e2..958e256 100644 --- a/Xcode/libusb.xcodeproj/project.pbxproj +++ b/Xcode/libusb.xcodeproj/project.pbxproj @@ -66,6 +66,32 @@ 20951C0625630F8F00ED6351 /* ezusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFDD1628BA0E00BC5BE2 /* ezusb.h */; }; 20951C0F25630FD300ED6351 /* libusb_testlib.h in Headers */ = {isa = PBXBuildFile; fileRef = 008A23CA236C849A004854AA /* libusb_testlib.h */; }; 20951C152563125200ED6351 /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; }; + CEA0F5EF26321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; }; + CEA0F5F026321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; }; + CEA0F5F126321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; }; + CEA0F5F226321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; + CEA0F5F326321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; }; + CEA0F5F426321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; }; + CEA0F5F526321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; + CEA0F5F626321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; }; + CEA0F5F726321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; }; + CEA0F5F826321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; + CEA0F5F926321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; }; + CEA0F5FA26321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; }; + CEA0F5FB26321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; + CEA0F5FC26321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; }; + CEA0F5FD26321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; }; + CEA0F5FE26321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; + CEA0F5FF26321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; }; + CEA0F60026321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; }; + CEA0F60126321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; + CEA0F60226321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; }; + CEA0F60326321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; }; + CEA0F60426321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; + CEA0F60526321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; }; + CEA0F60626321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; }; + CEA0F60726321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; + CEA45DFB2634CDFA002FA97D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEDCEA6E2632200A00F7AA49 /* Security.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -254,6 +280,7 @@ 20468D6E243298C100650534 /* sam3u_benchmark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sam3u_benchmark.c; sourceTree = ""; usesTabs = 1; }; 20468D75243298D300650534 /* testlibusb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testlibusb; sourceTree = BUILT_PRODUCTS_DIR; }; 20468D7C2432990000650534 /* testlibusb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testlibusb.c; sourceTree = ""; usesTabs = 1; }; + CEDCEA6E2632200A00F7AA49 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -261,7 +288,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, + CEA0F5F826321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -269,7 +296,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, + CEA0F60126321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -279,6 +306,7 @@ files = ( 008FBFAB1628B8CB00BC5BE2 /* libobjc.dylib in Frameworks */, 008FBFA91628B88000BC5BE2 /* IOKit.framework in Frameworks */, + CEA45DFB2634CDFA002FA97D /* Security.framework in Frameworks */, 008FBFA71628B87000BC5BE2 /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -287,7 +315,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, + CEA0F60726321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -303,7 +331,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, + CEA0F5F226321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -311,7 +339,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, + CEA0F5F526321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -319,7 +347,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, + CEA0F5FB26321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -327,7 +355,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, + CEA0F5FE26321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -335,7 +363,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, + CEA0F60426321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -453,6 +481,7 @@ 008FBFAA1628B8CB00BC5BE2 /* libobjc.dylib */, 008FBFA81628B88000BC5BE2 /* IOKit.framework */, 008FBFA61628B87000BC5BE2 /* CoreFoundation.framework */, + CEDCEA6E2632200A00F7AA49 /* Security.framework */, ); name = Apple; path = ../libusb; @@ -481,7 +510,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 008FBFA51628B84200BC5BE2 /* config.h in Headers */, + CEA0F5EF26321FAA00ADF3EC /* config.h in Headers */, 20951C152563125200ED6351 /* libusb.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -490,8 +519,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 008FBFA51628B84200BC5BE2 /* config.h in Headers */, - 20951C152563125200ED6351 /* libusb.h in Headers */, + CEA0F5F026321FAA00ADF3EC /* config.h in Headers */, + CEA0F5F126321FAA00ADF3EC /* libusb.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -499,9 +528,9 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 008FBFA51628B84200BC5BE2 /* config.h in Headers */, + CEA0F5F326321FAA00ADF3EC /* config.h in Headers */, 20951C0625630F8F00ED6351 /* ezusb.h in Headers */, - 20951C152563125200ED6351 /* libusb.h in Headers */, + CEA0F5F426321FAA00ADF3EC /* libusb.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -509,8 +538,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 008FBFA51628B84200BC5BE2 /* config.h in Headers */, - 20951C152563125200ED6351 /* libusb.h in Headers */, + CEA0F5F626321FAA00ADF3EC /* config.h in Headers */, + CEA0F5F726321FAA00ADF3EC /* libusb.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -518,8 +547,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 008FBFA51628B84200BC5BE2 /* config.h in Headers */, - 20951C152563125200ED6351 /* libusb.h in Headers */, + CEA0F5F926321FAA00ADF3EC /* config.h in Headers */, + CEA0F5FA26321FAA00ADF3EC /* libusb.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -527,8 +556,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 008FBFA51628B84200BC5BE2 /* config.h in Headers */, - 20951C152563125200ED6351 /* libusb.h in Headers */, + CEA0F5FC26321FAA00ADF3EC /* config.h in Headers */, + CEA0F5FD26321FAA00ADF3EC /* libusb.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -536,9 +565,9 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 008FBFA51628B84200BC5BE2 /* config.h in Headers */, + CEA0F5FF26321FAA00ADF3EC /* config.h in Headers */, 20951C0F25630FD300ED6351 /* libusb_testlib.h in Headers */, - 20951C152563125200ED6351 /* libusb.h in Headers */, + CEA0F60026321FAA00ADF3EC /* libusb.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -546,8 +575,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 008FBFA51628B84200BC5BE2 /* config.h in Headers */, - 20951C152563125200ED6351 /* libusb.h in Headers */, + CEA0F60226321FAA00ADF3EC /* config.h in Headers */, + CEA0F60326321FAA00ADF3EC /* libusb.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -555,8 +584,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 008FBFA51628B84200BC5BE2 /* config.h in Headers */, - 20951C152563125200ED6351 /* libusb.h in Headers */, + CEA0F60526321FAA00ADF3EC /* config.h in Headers */, + CEA0F60626321FAA00ADF3EC /* libusb.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/configure.ac b/configure.ac index 7c86598..5899fc2 100644 --- a/configure.ac +++ b/configure.ac @@ -161,7 +161,7 @@ fi case $backend in darwin) AC_CHECK_FUNCS([pthread_threadid_np]) - LIBS="${LIBS} -lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation" + LIBS="${LIBS} -lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation -Wl,-framework,Security" ;; haiku) LIBS="${LIBS} -lbe" diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c index 988ca9e..2e64038 100644 --- a/libusb/os/darwin_usb.c +++ b/libusb/os/darwin_usb.c @@ -172,6 +172,7 @@ static void darwin_deref_cached_device(struct darwin_cached_device *cached_dev) (*(cached_dev->device))->Release(cached_dev->device); cached_dev->device = NULL; } + IOObjectRelease (cached_dev->service); free (cached_dev); } } @@ -1057,6 +1058,9 @@ static enum libusb_error darwin_get_cached_device(io_service_t service, struct d (*device)->GetLocationID (device, &new_device->location); new_device->port = port; new_device->parent_session = parent_sessionID; + } else { + /* release the ref to old device's service */ + IOObjectRelease (new_device->service); } /* keep track of devices regardless of if we successfully enumerate them to @@ -1065,6 +1069,10 @@ static enum libusb_error darwin_get_cached_device(io_service_t service, struct d new_device->session = sessionID; new_device->device = device; + new_device->service = service; + + /* retain the service */ + IOObjectRetain (service); /* cache the device descriptor */ ret = darwin_cache_device_descriptor(new_device); @@ -2294,6 +2302,34 @@ static int darwin_free_streams (struct libusb_device_handle *dev_handle, unsigne #if InterfaceVersion >= 700 +/* macOS APIs for getting entitlement values */ + +#if TARGET_OS_OSX +#include +#else +typedef struct __SecTask *SecTaskRef; +extern SecTaskRef SecTaskCreateFromSelf(CFAllocatorRef allocator); +extern CFTypeRef SecTaskCopyValueForEntitlement(SecTaskRef task, CFStringRef entitlement, CFErrorRef *error); +#endif + +static bool darwin_has_capture_entitlements (void) { + SecTaskRef task; + CFTypeRef value; + bool entitled; + + task = SecTaskCreateFromSelf (kCFAllocatorDefault); + if (task == NULL) { + return false; + } + value = SecTaskCopyValueForEntitlement(task, CFSTR("com.apple.vm.device-access"), NULL); + CFRelease (task); + entitled = value && (CFGetTypeID (value) == CFBooleanGetTypeID ()) && CFBooleanGetValue (value); + if (value) { + CFRelease (value); + } + return entitled; +} + static int darwin_reload_device (struct libusb_device_handle *dev_handle) { struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); enum libusb_error err; @@ -2325,6 +2361,19 @@ static int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, } if (dpriv->capture_count == 0) { + /* request authorization */ + if (darwin_has_capture_entitlements ()) { + kresult = IOServiceAuthorize (dpriv->service, kIOServiceInteractionAllowed); + if (kresult != kIOReturnSuccess) { + usbi_err (HANDLE_CTX (dev_handle), "IOServiceAuthorize: %s", darwin_error_str(kresult)); + return darwin_to_libusb (kresult); + } + /* we need start() to be called again for authorization status to refresh */ + err = darwin_reload_device (dev_handle); + if (err != LIBUSB_SUCCESS) { + return err; + } + } /* reset device to release existing drivers */ err = darwin_reenumerate_device (dev_handle, true); if (err != LIBUSB_SUCCESS) { diff --git a/libusb/os/darwin_usb.h b/libusb/os/darwin_usb.h index 179341c..201dc36 100644 --- a/libusb/os/darwin_usb.h +++ b/libusb/os/darwin_usb.h @@ -171,6 +171,7 @@ struct darwin_cached_device { USBDeviceAddress address; char sys_path[21]; usb_device_t **device; + io_service_t service; int open_count; UInt8 first_config, active_config, port; int can_enumerate; diff --git a/libusb/version_nano.h b/libusb/version_nano.h index fcbf3cd..7d8c211 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 11612 +#define LIBUSB_NANO 11613 -- 2.7.4