Reputation: 11
I am trying to build a custom kernel extension for macOS catalina 10.15.7 and XCode 12.4 to access a third-party USB-Wifi dongle (Alfa Network AWUS036NHA with Atheros AR9271 chipset). Since the manufacturer does not officially support macOS Catalina 10.15 and later versions, the Wifi dongle must be accessed via custom USB drivers.
I found a promising repository that claims support for this chipset: https://github.com/T1T4N/Atheros-AR9271. Building the kernel extension succeeds, however, loading fails.
Anyway, you can pretty much ignore the background since I think this is a general problem in custom kernel development for latest macOS versions.
There are two ways of loading a kext from an untrusted source. First by completely or partially disabling SIP via
# in recovery mode:
$ csrutil disable
$ csrutil enable --without kext
or second, by adding the TEAMID to the trusted sources
$ codesign --display --verbose <name-of-kext>
# do this in recovery mode:
$ /usr/sbin/spctl kext-consent add <TEAMID>
I went with the first option and disabled SIP completely for now. I am fully aware of the consequences of disabling SIP and will later enable SIP again.
The driver, which I want to compile, relies on the following function call to the StandardUSB.h
library. This header is part of the IOKit
kext.
CleanAtheros.cpp
...
funcDesc = (const FunctionalDescriptorHeader *) StandardUSB::getNextDescriptorWithType(fInterface->getConfigurationDescriptor(), (const Descriptor *) funcDesc, CS_INTERFACE);
...
I successfully compiled the code and tried to load the kext with the following commands:
$ sudo chmod -R 755 CleanAtheros.kext
$ sudo chown -R root:wheel CleanAtheros.kext
$ sudo kextutil -v CleanAtheros.kext
This gave me the output:
> Defaulting to kernel file '/System/Library/Kernels/kernel'
> Notice: /Users/kesenheimer/tools/Atheros-AR9271/CleanAtheros.kext has debug properties set.
> Kext with invalid signature (-67050) allowed: <OSKext 0x7ff510d2f1b0 [0x7fff85288ce0]> { URL = "file:///Users/kesenheimer/tools/Atheros-AR9271/CleanAtheros.kext/", ID = "com.gubawang.AR9271.CleanAtheros" }
> Code Signing Failure: code signature is invalid
> /Users/kesenheimer/tools/Atheros-AR9271/CleanAtheros.kext appears to be loadable (not including linkage for on-disk libraries).
> Loading /Users/kesenheimer/tools/Atheros-AR9271/CleanAtheros.kext.
> Disabling KextAudit: SIP is off
> KextAudit initialized: audit=F
> (kernel) Notice - new kext com.apple.driver.usb.AppleUSBHostPlatformProperties, v1.2 matches prelinked kext but can't determine if executables are the same (no UUIDs).
> (kernel) kxld[com.gubawang.AR9271.CleanAtheros]: The following symbols are unresolved for this kext:
> (kernel) kxld[com.gubawang.AR9271.CleanAtheros]: __ZN11StandardUSB25getNextDescriptorWithTypeEPKNS_23ConfigurationDescriptorEPKNS_10DescriptorEh
> (kernel) kxld[com.gubawang.AR9271.CleanAtheros]: __ZN15IOUSBHostDevice9metaClassE
> (kernel) Can't load kext com.gubawang.AR9271.CleanAtheros - link failed.
> (kernel) Failed to load executable for kext com.gubawang.AR9271.CleanAtheros.
> (kernel) Kext com.gubawang.AR9271.CleanAtheros failed to load (0xdc008016).
> (kernel) Failed to load kext com.gubawang.AR9271.CleanAtheros (error 0xdc008016).
> Failed to load /Users/kesenheimer/tools/Atheros-AR9271/CleanAtheros.kext - (libkern/kext) link error.
> Failed to load /Users/kesenheimer/tools/Atheros-AR9271/CleanAtheros.kext - (libkern/kext) link error.
> Check library declarations for your kext with kextlibs(8).
Note the two error messages:
> (kernel) kxld[com.gubawang.AR9271.CleanAtheros]: The following symbols are unresolved for this kext:
> (kernel) kxld[com.gubawang.AR9271.CleanAtheros]: __ZN11StandardUSB25getNextDescriptorWithTypeEPKNS_23ConfigurationDescriptorEPKNS_10DescriptorEh
> (kernel) kxld[com.gubawang.AR9271.CleanAtheros]: __ZN15IOUSBHostDevice9metaClassE
When I search for the missing symbols, I get the kext module where these symbols are defined:
$ kextfind -dsym "__ZN11StandardUSB25getNextDescriptorWithTypeEPKNS_23ConfigurationDescriptorEPKNS_10DescriptorEh"
> /System/Library/Extensions/IOUSBHostFamily.kext
$ kextfind -dsym "__ZN15IOUSBHostDevice9metaClassE"
> /System/Library/Extensions/IOUSBHostFamily.kext
which seems to be fine. I have verified that this kext is loaded:
$ kextstat | grep "com.apple.iokit.IOUSBHostFamily"
> 27 20 0xffffff7f8112e000 0xfa000 0xfa000 com.apple.iokit.IOUSBHostFamily (1.2) 14D49A36-567A-3AA7-9449-EA6615643E1A <26 25 24 8 7 6 5 3 1>
Additionally, as suggested by the output above, I checked with kextlibs which kernel extensions are needed by the kext:
$ kextlibs CleanAtheros.kext
> For x86_64:
> com.apple.iokit.IOUSBHostFamily = 1.2
> com.apple.kpi.iokit = 19.6
> com.apple.kpi.libkern = 19.6
> For arm64e:
> No libraries found.
>
> 297 symbols not found in any library kext.
I can not figure out how to resolve the missing symbols. These are my questions:
code signature is invalid
.IOUSBHost.framework
to the project, since the missing symbols are defined in this framework as well. However, the symbols can still not be found, and attempts to sign the kext fail.Additionally, here are my attempts changing the build settings:
Hope, anyone has a better insight than me in this case...
Upvotes: 0
Views: 852
Reputation: 23428
So, I originally assumed there was actual driver code here that worked on previous macOS versions. Looking deeper and following the source code link makes it clear that this is just a fragment of code for a driver somebody started but with which they apparently didn't get very far. So this code will never have worked as a network driver on any version of macOS/OS X.
For the sake of completeness, the immediate linking problem arises from listing IOUSBFamily
(used prior to OS X 10.11) in the dependencies:
<key>OSBundleLibraries</key>
<dict>
<key>com.apple.iokit.IOUSBFamily</key>
<string>705.4.14</string>
whereas the actual code uses the more modern but already deprecated IOUSBHostFamily
:
#include <IOKit/usb/IOUSBHostDevice.h>
So the solution for the link errors is to link against com.apple.iokit.IOUSBHostFamily
instead.
The solution to your actual problem of using an unsupported network device on modern macOS is:
You'll need to build a new driver from scratch, based on USBDriverKit
and NetworkingDriverKit
. The details of this are of course outside the scope of a Stack Overflow answer.
(Factually not incorrect, but as it turns out, not the biggest problem here.)
Xcode 12.4 ships with the macOS 11.1 SDK. Unlike in user space, for kexts, you should use the SDK for the oldest macOS version you are targeting.
According to xcodereleases.com, Xcode version 12.1.1 is the last to ship with an SDK for 10.15.x (10.15.6 specifically), so in my opinion that would be the first thing to try: use Xcode 12.1.1 or an older version to build your kext.
And yes, this can become problematic when the older Xcode version no longer runs on your modern version of macOS; there's no good alternative to simply keeping either a VM or real Mac around that still runs a compatible macOS version. Trying to mix and match older SDKs with newer Xcode versions tends to be more trouble than it's worth (and sometimes doesn't work anyway).
Note that both the networking and USB family kernel APIs are deprecated, so you might find that the kext stops working altogether in a later version of macOS; you certainly can no longer use them with SIP enabled.
Regarding code signing:
This has mostly been tackled in various previous questions and answers, e.g.:
Essentially, you need a special variant of "Developer ID" certificate from Apple (which they rarely grant these days), and you subsequently need to notarise the kext. Neither will help you though, as you're linking against obsolete kernel APIs, which is only allowed if SIP is disabled, which in turn means there is no kext signing requirement anyway.
Long term:
As I've pointed out, this may work as a short term solution, but probably won't work in all future macOS versions. Eventually, the driver will need to be ported to DriverKit to be able to continue using it.
Upvotes: 1