Posts under App & System Services topic

Post

Replies

Boosts

Views

Activity

Sandboxed applications fail to mount NFS using NetFSMountURLSync
Mounting NFS to the application's own container directory using NetFSMountURLSync failed. Mounted to /Users/li/Library/Containers/com.xxxxx.navm.MyNavm/Data/Documents/NFSMount Do sandbox applications not allow mounting NFS cloud storage? code: // 1. NFS 服务器 URL(指定 NFSv3) let urlString = "nfs://192.168.64.4/seaweed?vers=3&resvport&nolocks&locallocks&soft&intr&timeo=600" guard let nfsURL = URL(string: urlString) else { os_log("❌ 无效的 URL: %@", log: netfsLog, type: .error, urlString) return } // 2. 挂载点(必须在沙盒容器内) let fileManager = FileManager.default guard let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { os_log("❌ 无法获取 Documents 目录", log: netfsLog, type: .error) return } let mountPointURL = documentsURL.appendingPathComponent("NFSMount", isDirectory: true) // 创建挂载点目录 do { try fileManager.createDirectory(at: mountPointURL, withIntermediateDirectories: true, attributes: nil) os_log("✅ 挂载点目录已准备: %@", log: netfsLog, type: .info, mountPointURL.path) } catch { os_log("❌ 创建挂载点目录失败: %@", log: netfsLog, type: .error, error.localizedDescription) return } // 3. 挂载选项(使用 NSMutableDictionary 以匹配 CFMutableDictionary) let mountOptions = NSMutableDictionary() // 如果需要,可以添加选项,例如: // mountOptions[kNetFSNoUserAuthenticationKey as String] = true // 4. 调用 NetFSMountURLSync var mountPoints: Unmanaged<CFArray>? = nil let status = NetFSMountURLSync( nfsURL as CFURL, mountPointURL as CFURL, nil, // user nil, // password nil, // open_options mountOptions, // 直接传递 NSMutableDictionary,自动桥接为 CFMutableDictionary &mountPoints ) log: 0 sandboxd: (TCC) [com.apple.TCC:cache] REMOVE: (kTCCServiceSystemPolicyAppData, <Credential (0x7ed0b4230) | Audit Token, 42834.109774/501>) 2026-03-03 21:38:27.656702+0800 0x2de8d8 Info 0x867e9d 408 0 sandboxd: (TCC) [com.apple.TCC:cache] SET: (kTCCServiceSystemPolicyAppData, <Credential (0x7ed0b4230) | Audit Token, 42834.109774/501>) -> <Authorization Record (0x7ecca8180) | Service: kTCCServiceSystemPolicyAppData, AuthRight: Unknown, Reason: None, Version: 1, Session pid: 42832, Session pid version: 109769, Boot UUID: 7DDB03FC-132C-4E56-BA65-5C858D2CC8DD, > 2026-03-03 21:38:27.656753+0800 0x2de8d8 Default 0x867e9d 408 0 sandboxd: (libxpc.dylib) [com.apple.xpc:connection] [0x7ecc88640] invalidated after the last release of the connection object 2026-03-03 21:38:27.656772+0800 0x2de8d8 Debug 0x867e9b 408 0 sandboxd: (TCC) [com.apple.TCC:access] disposing: 0x7ecc3aa80(OS_tcc_message_options) 2026-03-03 21:38:27.656779+0800 0x2de8d8 Debug 0x867e9b 408 0 sandboxd: (TCC) [com.apple.TCC:access] disposing: 0x7ecc44820(OS_tcc_server) 2026-03-03 21:38:27.656788+0800 0x2de8d8 Info 0x867e9b 408 0 sandboxd: [com.apple.sandbox:sandcastle] kTCCServiceSystemPolicyAppData would require prompt by TCC for mount_nfs
0
0
23
9h
Unix Domain Socket path for IPC between LaunchDaemon and LaunchAgent
Hello, I am working on a cross-platform application where IPC between a LaunchDaemon and a LaunchAgent is implemented via Unix domain sockets. On macOS, the socket path length is restricted to 104 characters. What is the Apple-recommended directory for these sockets to ensure the path remains under the limit while allowing a non-sandboxed agent to communicate with a root daemon? Standard paths like $TMPDIR are often too long for this purpose. Thank you in advance!
0
0
19
9h
Getting a basic URL Filter to work
I haven’t been able to get this to work at any level! I’m running into multiple issues, any light shed on any of these would be nice: I can’t implement a bloom filter that produces the same output as can be found in the SimpleURLFilter sample project, after following the textual description of it that’s available in the documentation. No clue what my implementation is doing wrong, and because of the nature of hashing, there is no way to know. Specifically: The web is full of implementations of FNV-1a and MurmurHash3, and they all produce different hashes for the same input. Can we get the proper hashes for some sample strings, so we know which is the “correct” one? Similarly, different implementations use different encodings for the strings to hash. Which should we use here? The formulas for numberOfBits and numberOfHashes give Doubles and assign them to Ints. It seems we should do this conversing by rounding them, is this correct? Can we get a sample correct value for the combined hash, so we can verify our implementations against it? Or ignoring all of the above, can we have the actual code instead of a textual description of it? 😓 I managed to get Settings to register my first attempt at this extension in beta 1. Now, in beta 2, any other project (including the sample code) will redirect to Settings, show the Allow/Deny message box, I tap Allow, and then nothing happens. This must be a bug, right? Whenever I try to enable the only extension that Settings accepted (by setting its isEnabled to true), its status goes to .stopped and the error is, of course, .unknown. How do I debug this? While the extension is .stopped, ALL URL LOADS are blocked on the device. Is this to be expected? (shouldFailClosed is set to false) Is there any way to manually reload the bloom filter? My app ships blocklist updates with background push, so it would be wasteful to fetch the filter at a fixed interval. If so, can we opt out of the periodic fetch altogether? I initially believed the API to be near useless because I didn’t know of its “fuzzy matching” capabilities, which I’ve discovered by accident in a forum post. It’d be nice if those were documented somewhere! Thanks!!
46
1
4.1k
9h
Request for Guidance on Approval Process for Network Extension Entitlement
Dear Apple Developer Support Team, I am writing to inquire about the process for obtaining approval for the following entitlement in my iOS/macOS app: <key>com.apple.developer.networking.networkextension</key> <array> <string>content-filter-provider</string> </array> Specifically, I would like guidance on: The steps required to submit a request for this entitlement. Any necessary documentation or justification that needs to be provided to Apple. Typical review timelines and approval criteria. Any restrictions or compliance requirements associated with this entitlement. Our app intends to implement a content filtering functionality to enhance network security and user safety. We want to ensure full compliance with Apple’s policies and guidelines. Could you please provide detailed instructions or point us to the relevant resources to initiate this approval process? Thank you for your assistance.
2
0
136
11h
Push notifications not delivered over Wi-Fi with includeAllNetworks = true regardless of excludeAPNS setting
We have a VPN app that uses NEPacketTunnelProvider with includeAllNetworks = true. We've encountered an issue where push notifications are not delivered over Wi-Fi while the tunnel is active in a pre-MFA quarantine state (tunnel is up but traffic is blocked on server side), regardless of whether excludeAPNS is set to true or false. Observed behavior Wi-Fi excludeAPNS = true - Notifications not delivered Wi-Fi excludeAPNS = false - Notifications not delivered Cellular excludeAPNS = true - Notifications delivered Cellular excludeAPNS = false - Notifications not delivered On cellular, the behavior matches our expectations: setting excludeAPNS = true allows APNS traffic to bypass the tunnel and notifications arrive; setting it to false routes APNS through the tunnel and notifications are blocked (as expected for a non-forwarding tunnel). On Wi-Fi, notifications fail to deliver in both cases. Our question Is this expected behavior when includeAllNetworks is enabled on Wi-Fi, or is this a known issue / bug with APNS delivery? Is there something else in the Wi-Fi networking path that includeAllNetworks affects beyond routing, which could prevent APNS from functioning even when the traffic is excluded from the tunnel? Sample Project Below is the minimal code that reproduces this issue. The project has two targets: a main app and a Network Extension. The tunnel provider captures all IPv4 and IPv6 traffic via default routes but does not forward packets — simulating a pre-MFA quarantine state. The main app configures the tunnel with includeAllNetworks = true and provides a UI toggle for excludeAPNS. PacketTunnelProvider.swift (Network Extension target): import NetworkExtension class PacketTunnelProvider: NEPacketTunnelProvider { override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1") let ipv4 = NEIPv4Settings(addresses: ["198.51.100.1"], subnetMasks: ["255.255.255.0"]) ipv4.includedRoutes = [NEIPv4Route.default()] settings.ipv4Settings = ipv4 let ipv6 = NEIPv6Settings(addresses: ["fd00::1"], networkPrefixLengths: [64]) ipv6.includedRoutes = [NEIPv6Route.default()] settings.ipv6Settings = ipv6 let dns = NEDNSSettings(servers: ["198.51.100.1"]) settings.dnsSettings = dns settings.mtu = 1400 setTunnelNetworkSettings(settings) { error in if let error = error { completionHandler(error) return } self.readPackets() completionHandler(nil) } } private func readPackets() { packetFlow.readPackets { [weak self] packets, protocols in self?.readPackets() } } override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { completionHandler() } override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { if let handler = completionHandler { handler(messageData) } } override func sleep(completionHandler: @escaping () -> Void) { completionHandler() } override func wake() { } } ContentView.swift (Main app target) — trimmed to essentials: import SwiftUI import NetworkExtension struct ContentView: View { @State private var excludeAPNs = false @State private var manager: NETunnelProviderManager? var body: some View { VStack { Toggle("Exclude APNs", isOn: $excludeAPNs) .onChange(of: excludeAPNs) { Task { await saveAndReload() } } Button("Connect") { Task { await toggleVPN() } } } .padding() .task { await loadManager() } } private func loadManager() async { let managers = try? await NETunnelProviderManager.loadAllFromPreferences() if let existing = managers?.first { manager = existing } else { let m = NETunnelProviderManager() let proto = NETunnelProviderProtocol() proto.providerBundleIdentifier = "<your-extension-bundle-id>" proto.serverAddress = "127.0.0.1" proto.includeAllNetworks = true proto.excludeAPNs = excludeAPNs m.protocolConfiguration = proto m.localizedDescription = "TestVPN" m.isEnabled = true try? await m.saveToPreferences() try? await m.loadFromPreferences() manager = m } if let proto = manager?.protocolConfiguration as? NETunnelProviderProtocol { excludeAPNs = proto.excludeAPNs } } private func saveAndReload() async { guard let manager else { return } if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol { proto.includeAllNetworks = true proto.excludeAPNs = excludeAPNs } manager.isEnabled = true try? await manager.saveToPreferences() try? await manager.loadFromPreferences() } private func toggleVPN() async { guard let manager else { return } if manager.connection.status == .connected { manager.connection.stopVPNTunnel() } else { await saveAndReload() try? manager.connection.startVPNTunnel() } } } Steps to reproduce Build and run the sample project with above code on a physical iOS device. Connect to a Wi-Fi network. Set excludeAPNS = true using the toggle and tap Connect. Send a push notification to the device to a test app with remote notification capability (e.g., via a test push service or the push notification console). Observe that the notification is not delivered. Disconnect. Switch to cellular. Reconnect with the same settings. Send the same push notification — observe that it is delivered. Environment iOS 26.2 Xcode 26.2 Physical device (iPhone 15 Pro)
3
1
75
11h
Random global network outage triggered by NEFilterDataProvider extension – only reboot helps, reinstall doesn't
I’m encountering a persistent issue with my Network Extension (specifically NEFilterDataProvider) and would really appreciate any insights. The extension generally works as expected, but after some time — especially after sleep/wake cycles or network changes — a global network outage occurs. During this state, no network traffic works: pings fail, browsers can’t load pages, etc. As soon as I stop the extension (by disabling it in System Preferences), the network immediately recovers. If I re-enable it, the outage returns instantly. I’ve also noticed that once this happens, the extension stops receiving callbacks like handleNewFlow(), and reinstalling the app or restarting the extension doesn’t help. The only thing that resolves the issue is rebooting the system. After reboot, the extension works fine again — until the problem reoccurs later. I asked AI about this behavior, and it suggested the possibility that the kernel might have marked the extension as untrusted, causing the system to intentionally block all network traffic as a safety mechanism. Has anyone experienced similar behavior with NEFilterDataProvider? Could there be a way to detect or prevent this state without rebooting? Is there any logging or diagnostic data I should collect when it happens again? Any guidance or pointers would be greatly appreciated. Thanks in advance!
3
0
62
11h
Get UDP/TCP Payload for NWConnections?
Is it somehow possible to get the transport layer (UDP and TCP) payload amounts for TLS or QUIC connections established via the Network framework? (From within the app itself that establishes the connections.) I am currently using the ntstat.h kernel socket calls, but I hope there is a simpler solution. With ntstat, I have not yet been able to observe a specific connection. I have to search for the connection I am looking in all (userspace) connections.
2
0
38
11h
StoreKit Sandbox – Unfinished Consumable Transaction Across Devices
I’d like to confirm the expected behavior of StoreKit 2 in the Sandbox environment regarding unfinished consumable transactions across devices. Scenario: Device A and Device B are signed in with the same Sandbox Apple ID A consumable in-app purchase is completed on Device A The transaction may be verified or unverified, but transaction.finish() is not called The app is then launched on Device B and listens for Transaction.updates Question: In this scenario, is it expected that Device B will or will not receive a callback for this unfinished consumable transaction? Or is it by design that unfinished consumable transactions are not guaranteed to be delivered across devices, regardless of verification state?
3
0
109
12h
Issues with diacritics in filename on iOS when the system main language is not English
Hi, I'm encountering a weird issue on iOS that happens: for files with diacritics in their name, like "Gòmez.pdf" or "Télé.mp4", when the iPhone or iPad main language is not set to English, if the file has been created with a relatively low-level Unix function like fopen() or copyfile(). Then, the file cannot be previsualized using QuickLook or opened using other apps. Most of the time it fails silently, but on some occasions I get the following error message: "You do not have permission to save the file "filename.pdf" in the folder "myFolder"". The issue is present in, at least, iOS 16 and 26. It seems worse in iOS 26. It seems that all three conditions are required, I don't see the issue when the iPhone or iPad is set to use English as the main language. I also don't see the issue if I rename the files in the Files app. I'm probably doing something wrong, but what can it be? (it's kind of weird that my recommendation for users becomes: if you want to use international characters in your file names, you need to set the iPad language to English...)
1
0
120
12h
Can a DeviceActivityReport extension pass the user’s daily Screen Time total back to the main app
Hi, I’m building an iOS self accountability app using FamilyControls and DeviceActivity. I can show the user’s real Screen Time correctly inside a DeviceActivityReport extension on a real device, but I want to use that same daily total inside the main app for today’s log and leaderboard. What I’m stuck on is getting that value back into the app. I tried App Groups, shared UserDefaults, a shared file in the app group container, and CFPreferences, but the report still only works as a display and the main app never receives the total. Is there any Apple supported way to use the daily Screen Time total from a DeviceActivityReport extension inside the containing app, or is this intentionally display only? Thanks.
1
0
45
12h
Problems with iPad Pro M4 13 inch
We have an iOS/iPadOS (mixed use of UIKit/SwiftUI) app on the App Store since a couple of years. Over the last month or so, we are receiving many user reports complaining about app freezing and behaving very bad generally. The common denominator for all of these users (~10) is that they are using iPad Pro M4, 13 inch, and they are on at least iPadOS 26.2 - some have updated to 26.2.1, 26.3 etc but the problems remain. Some of the users say that they were using our app normally, until the release of 26.2, or perhaps 26.2.1, from when the problems seem to have started. Some report the problems that go away when they "use another WiFi", or when they hold the device in portrait mode (it seems that many complaints seem to suggest that the problem is in when holding the device in landscape). Other say the app works fine if they start it without network enabled, and after enabling network, continue in the app. While we currently do not have an iPad Pro M4 13 inch to test with, we haven't been able to reproduce the problem on any other device. We haven't heard of any similar problems from users of other devices. While we have no idea what is causing these problems, my feeling is that there might be a possibility that there is some kind of problem with iPad Pro M4 and the recent iPadOS versions. Just reaching out to see if anyone else have seen anything similar.
1
0
66
13h
Sharing all container content
I've understood that SwiftData is not abled to share the whole content of a cloudkit database. So I'm trying to rewrite everything. Does someone knows id Sharing is coming on SwiftData at WWDC 26? Anyway, can someone can point me an example a a configured coredata stack that share all its content with other icloud users (with sharing pane and accept invitation code). At this step, on the owner side, I see some data in the default zone of my private container but nothing is visible on the shared zone. Maybe I don't understand where and when I should check shared data in cloudkit console. Need Help also here. See below by configuration stack: // Core Data container public lazy var container: NSPersistentContainer = { switch delegate.usage() { case .preview : return previewContainer() case .local : return localContainer() case .cloudKit : return cloudKitContainer() } }() private func cloudKitContainer() -> NSPersistentContainer { let modelURL = delegate.modelURL() let modelName = modelURL.deletingPathExtension().lastPathComponent guard let model = NSManagedObjectModel(contentsOf: modelURL) else { fatalError("Could not load Core Data model from \(modelURL)") } let container = NSPersistentCloudKitContainer( name: modelName, managedObjectModel: model ) let groupIdentifier = AppManager.shared.groupIdentifier guard let appGroupURL = FileManager.default.containerURL ( forSecurityApplicationGroupIdentifier: groupIdentifier ) else { fatalError("App Group not found: \(groupIdentifier)") } // MARK: - Private Store Configuration let privateStoreURL = appGroupURL.appendingPathComponent("\(modelName).sqlite") let privateStoreDescription = NSPersistentStoreDescription(url: privateStoreURL) // Persistent history tracking (MANDATORY) privateStoreDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) privateStoreDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) // CloudKit options for private database // Core Data automatically uses the default zone: com.apple.coredata.cloudkit.zone let privateCloudKitOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: delegate.cloudKitIdentifier()) privateCloudKitOptions.databaseScope = .private privateStoreDescription.cloudKitContainerOptions = privateCloudKitOptions // MARK: - Shared Store Configuration guard let sharedStoreDescription = privateStoreDescription.copy() as? NSPersistentStoreDescription else { fatalError("Create shareDesc error") } // The shared store receives zones that others share with us via CloudKit's shared database sharedStoreDescription.url = appGroupURL.appendingPathComponent("\(modelName)-shared.sqlite") // Persistent history tracking (MANDATORY) sharedStoreDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) sharedStoreDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) // CloudKit options for shared database // This syncs data from CloudKit shared zones when we accept share invitations let sharedCloudKitOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: delegate.cloudKitIdentifier()) sharedCloudKitOptions.databaseScope = .shared sharedStoreDescription.cloudKitContainerOptions = sharedCloudKitOptions // Configure both stores // Private store: com.apple.coredata.cloudkit.zone in private database // Shared store: Receives shared zones we're invited to container.persistentStoreDescriptions = [privateStoreDescription, sharedStoreDescription] container.loadPersistentStores { storeDescription, error in if let error = error as NSError? { fatalError("DB init error:\(error.localizedDescription)") } else if let cloudKitContiainerOptions = storeDescription.cloudKitContainerOptions { switch cloudKitContiainerOptions.databaseScope { case .private: self._privatePersistentStore = container.persistentStoreCoordinator.persistentStore(for: privateStoreDescription.url!) case .shared: self._sharedPersistentStore = container.persistentStoreCoordinator.persistentStore(for: sharedStoreDescription.url!) default: break } } let scope = storeDescription.cloudKitContainerOptions?.databaseScope == .shared ? "shared" : "private" print("✅ \(scope) store loaded at: \(storeDescription.url?.path ?? "unknown")") } // Auto-merge container.viewContext.automaticallyMergesChangesFromParent = true container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy do { try container.viewContext.setQueryGenerationFrom(.current) } catch { fatalError("Fail to pin viewContext to the current generation:\(error)") } return container }
3
0
76
14h
Can't get USBSerialDriverKit driver loaded
I am writing a DriverKit driver for the first that uses the USBSerialDriverKit. The driver its purpose is to expose the device as serial interface (/dev/cu.tetra-pei0 or something like this). My problem: I don't see any logs from that driver in the console and I tried like 40 different approaches and checked everything. The last message I see is that the driver get successfully added to the system it is in the list of active and enabled system driver extensions but when I plug the device in none of my logs appear and it doesn't show up in ioreg. So without my driver the target device looks like this: +-o TETRA PEI interface@02120000 <class IOUSBHostDevice, id 0x10000297d, registered, matched, active, busy 0 (13 ms), retain 30> | { | "sessionID" = 268696051410 | "USBSpeed" = 3 | "UsbLinkSpeed" = 480000000 | "idProduct" = 36886 | "iManufacturer" = 1 | "bDeviceClass" = 0 | "IOPowerManagement" = {"PowerOverrideOn"=Yes,"DevicePowerState"=2,"CurrentPowerState"=2,"CapabilityFlags"=32768,"MaxPowerState"=2,"DriverPowerState"=0} | "bcdDevice" = 9238 | "bMaxPacketSize0" = 64 | "iProduct" = 2 | "iSerialNumber" = 0 | "bNumConfigurations" = 1 | "UsbDeviceSignature" = <ad0c16901624000000ff0000> | "USB Product Name" = "TETRA PEI interface" | "locationID" = 34734080 | "bDeviceSubClass" = 0 | "bcdUSB" = 512 | "USB Address" = 6 | "kUSBCurrentConfiguration" = 1 | "IOCFPlugInTypes" = {"9dc7b780-9ec0-11d4-a54f-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"} | "UsbPowerSinkAllocation" = 500 | "bDeviceProtocol" = 0 | "USBPortType" = 0 | "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb")) | "USB Vendor Name" = "Motorola Solutions, Inc." | "Device Speed" = 2 | "idVendor" = 3245 | "kUSBProductString" = "TETRA PEI interface" | "kUSBAddress" = 6 | "kUSBVendorString" = "Motorola Solutions, Inc." | } | +-o AppleUSBHostCompositeDevice <class AppleUSBHostCompositeDevice, id 0x100002982, !registered, !matched, active, busy 0, retain 5> | { | "IOProbeScore" = 50000 | "CFBundleIdentifier" = "com.apple.driver.usb.AppleUSBHostCompositeDevice" | "IOProviderClass" = "IOUSBHostDevice" | "IOClass" = "AppleUSBHostCompositeDevice" | "IOPersonalityPublisher" = "com.apple.driver.usb.AppleUSBHostCompositeDevice" | "bDeviceSubClass" = 0 | "CFBundleIdentifierKernel" = "com.apple.driver.usb.AppleUSBHostCompositeDevice" | "IOMatchedAtBoot" = Yes | "IOMatchCategory" = "IODefaultMatchCategory" | "IOPrimaryDriverTerminateOptions" = Yes | "bDeviceClass" = 0 | } | +-o lghub_agent <class AppleUSBHostDeviceUserClient, id 0x100002983, !registered, !matched, active, busy 0, retain 7> | { | "IOUserClientCreator" = "pid 1438, lghub_agent" | "IOUserClientDefaultLocking" = Yes | } | +-o IOUSBHostInterface@0 <class IOUSBHostInterface, id 0x100002986, registered, matched, active, busy 0 (5 ms), retain 9> | | { | | "USBPortType" = 0 | | "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"} | | "USB Vendor Name" = "Motorola Solutions, Inc." | | "bcdDevice" = 9238 | | "USBSpeed" = 3 | | "idProduct" = 36886 | | "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb")) | | "bInterfaceSubClass" = 0 | | "bConfigurationValue" = 1 | | "locationID" = 34734080 | | "USB Product Name" = "TETRA PEI interface" | | "bInterfaceProtocol" = 0 | | "iInterface" = 0 | | "bAlternateSetting" = 0 | | "idVendor" = 3245 | | "bInterfaceNumber" = 0 | | "bInterfaceClass" = 255 | | "bNumEndpoints" = 2 | | } | | | +-o lghub_agent <class AppleUSBHostInterfaceUserClient, id 0x100002988, !registered, !matched, active, busy 0, retain 6> | { | "UsbUserClientBufferStatistics" = {"IOMemoryDescriptor"=0,"IOBufferMemoryDescriptor"=0,"IOSubMemoryDescriptor"=0} | "IOUserClientCreator" = "pid 1438, lghub_agent" | "UsbUserClientBufferAllocations" = {"Bytes"=0,"Descriptors"=0} | "IOUserClientDefaultLocking" = Yes | } | +-o IOUSBHostInterface@1 <class IOUSBHostInterface, id 0x100002987, registered, matched, active, busy 0 (5 ms), retain 9> | { | "USBPortType" = 0 | "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"} | "USB Vendor Name" = "Motorola Solutions, Inc." | "bcdDevice" = 9238 | "USBSpeed" = 3 | "idProduct" = 36886 | "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb")) | "bInterfaceSubClass" = 0 | "bConfigurationValue" = 1 | "locationID" = 34734080 | "USB Product Name" = "TETRA PEI interface" | "bInterfaceProtocol" = 0 | "iInterface" = 0 | "bAlternateSetting" = 0 | "idVendor" = 3245 | "bInterfaceNumber" = 1 | "bInterfaceClass" = 255 | "bNumEndpoints" = 2 | } | +-o lghub_agent <class AppleUSBHostInterfaceUserClient, id 0x10000298a, !registered, !matched, active, busy 0, retain 6> { "UsbUserClientBufferStatistics" = {"IOMemoryDescriptor"=0,"IOBufferMemoryDescriptor"=0,"IOSubMemoryDescriptor"=0} "IOUserClientCreator" = "pid 1438, lghub_agent" "UsbUserClientBufferAllocations" = {"Bytes"=0,"Descriptors"=0} "IOUserClientDefaultLocking" = Yes } more details in my comment.
6
0
56
21h
macOS 26.4 Beta breaks keyboard remapping for built-in MacBook keyboards – significant ecosystem impact
Since macOS 26.4 Beta 1, virtual HID devices created via DriverKit can no longer intercept key events from the built-in MacBook keyboard. External keyboards still work. This is confirmed and tracked here: https://github.com/pqrs-org/Karabiner-Elements/issues/4402 One possible lead (from LLM-assisted analysis of Apple's open-source IOHIDFamily code and cross-referencing community reports): macOS 26.4 Beta may have introduced or modified a security policy referred to as com.apple.iohid.protectedDeviceAccess, which could block IOHIDDeviceOpen for the Apple Internal Keyboard connected via SPI transport (AppleHIDTransportHIDDevice). This appears related to a "GamePolicy" check in IOHIDDeviceClass.m that gates whether processes can open HID devices. This has not been independently verified and may or may not be the root cause. This has far-reaching consequences. Karabiner-Elements alone has over 21,000 GitHub stars and is used by hundreds of thousands of macOS users for keyboard customization, accessibility workflows, ergonomic setups, and multilingual input. This change completely breaks its core functionality on any MacBook. Beyond Karabiner, this affects every developer building keyboard remapping, input customization, or accessibility tooling via DriverKit virtual HID devices — including commercial applications currently in development. I'd argue that the power and flexibility of keyboard customization on macOS is a genuine competitive advantage for the platform. Developers and power users choose Macs partly because tools like this exist. Restricting this capability would be detrimental to the ecosystem and to Apple's appeal among professional users. I'd like to understand: is this an intentional security change or a regression? If intentional, is there a migration path?
1
0
38
21h
Driver Activation failure error code 9. Maybe Entitlements? Please help
This is my first driver and I have had the devil of a time trying to find any information to help me with this. I beg help with this, since I cannot find any tutorials that will get me over this problem. I am attempting to write a bridging driver for an older UPS that only communicates via RPC-over-USB rather than the HID Power Device class the OS requires. I have written the basic framework for the driver (details below) and am calling OSSystemExtensionRequest.submitRequest with a request object created by OSSystemExtensionRequest.activationRequest, but the didFailWithError callback is called with OSSystemExtensionErrorDomain of a value of 9, which appears to be a general failure to activate the driver. I can find no other information on how to address this issue, but I presume the issue is one of entitlements in either the entitlements file or Info.plist. I will have more code-based details below. For testing context, I am testing this on a 2021 iMac (M1) running Sequoia 15.7, and this iMac is on MDM, specifically Jamf. I have disabled SIP and set systemextensionsctl developer on, per the instructions here, and I have compiled and am attempting to debug the app using xcode 26.2. The driver itself targets DriverKit 25, as 26 does not appear to be available in xcode despite hints on google that it's out. For the software, I have a two-target structure in my xcode project, the main Manager app, which is a swift-ui app that both handles installation/activation of the driver and (if that finally manages to work) handles communication from the driver via its UserClient, and the driver which compiles as a dext. Both apps compile and use automated signing attached to our Apple Development team. I won't delve into the Manager app much, as it runs even though activation fails, except to include its entitlements file in case it proves relevant <dict> <key>com.apple.developer.driverkit.communicates-with-drivers</key> <true/> <key>com.apple.developer.system-extension.install</key> <true/> <key>com.apple.security.app-sandbox</key> <true/> <key>com.apple.security.files.user-selected.read-only</key> <true/> </dict> and the relevant activation code: func request(_ request: OSSystemExtensionRequest, didFailWithError error: any Error) { // handling the error, which is always code value 9 } func activateDriver() { let request = OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: "com.mycompany.driver.bundle.identifier", queue: .main) request.delegate = self OSSystemExtensionManager.shared.submitRequest(request) //... } And finally the Manager app has the following capabilities requested for its matching identifier in our Apple Developer Account: DriverKit Communicates with Drivers System Extension On the Driver side, I have two major pieces, the main driver class MyDriver, and UserClient class, StatusUserClient. MyDriver derives from IDriverKit/IOService.iig but (in case this is somehow important) does not have the same name as the project/target name MyBatteryDriver. StatusUserClient derives from DriverKit/IOUserClient.iig. I have os_log(OS_LOG_DEFAULT, "trace messages") code in every method of both classes, including the initializers and Start implementations, and the log entries never seem to show up in Console, so I presume that means the OS never tried to load the driver. Unless I'm looking in the wrong place? Because I don't think the driver code is the current issue, I won't go into it unless it becomes necessary. As I mentioned above, I think this is a code signing / entitlements issue, but I don't know how to resolve it. In our Apple Developer account, the Driver's matching identifier has the following capabilities requested: DriverKit (development) DriverKit Allow Any UserClient (development) DriverKit Family HID Device (development) -- NOTE: this is planned for future use, but not yet implemented by my driver code. Could that be part of the problem? DriverKit Transport HID (development) DriverKit USB Transport (development) DriverKit USB Transport - VendorID -- submitted, no response from Apple yet HID Virtual Device -- submitted, no response from Apple. yet. This is vestigial from an early plan to build the bridge via shared memory funneling to a virtual HID device. I think I've found a way to do it with one Service, but... not sure yet. Still, that's a problem for tomorrow. Apparently I've gone over the 7000 character maximum so I will add my entitlements and info.plist contents in a reply.
4
0
212
21h
Basic introduction to DEXT Matching and Loading
Note: This document is specifically focused on what happens after a DEXT has passed its initial code-signing checks. Code-signing issues are dealt with in other posts. Preliminary Guidance: Using and understanding DriverKit basically requires understanding IOKit, something which isn't entirely clear in our documentation. The good news here is that IOKit actually does have fairly good "foundational" documentation in the documentation archive. Here are a few of the documents I'd take a look at: IOKit Fundamentals IOKit Device Driver Design Guidelines Accessing Hardware From Applications Special mention to QA1075: "Making sense of IOKit error codes",, which I happened to notice today and which documents the IOReturn error format (which is a bit weird on first review). Those documents do not cover the full DEXT loading process, but they are the foundation of how all of this actually works. Understanding the IOKitPersonalities Dictionary The first thing to understand here is that the "IOKitPersonalities" is called that because it is in fact a fully valid "IOKitPersonalities" dictionary. That is, what the system actually uses that dictionary "for" is: Perform a standard IOKit match and load cycle in the kernel. The final driver in the kernel then uses the DEXT-specific data to launch and run your DEXT process outside the kernel. So, working through the critical keys in that dictionary: "IOProviderClass"-> This is the in-kernel class that your in-kernel driver loads "on top" of. The IOKit documentation and naming convention uses the term "Nub", but the naming convention is not consistent enough that it applies to all cases. "IOClass"-> This is the in-kernel class that your driver loads on top of. This is where things can become a bit confused, as some families work by: Routing all activity through the provider reference so that the DEXT-specific class does not matter (PCIDriverKit). Having the DEXT subclass a specific subclass which corresponds to a specific kernel driver (SCSIPeripheralsDriverKit). This distinction is described in the documentation, but it's easy to overlook if you don't understand what's going on. However, compare PCIDriverKit: "When the system loads your custom PCI driver, it passes an IOPCIDevice object as the provider to your driver. Use that object to read and write the configuration and memory of your PCI hardware." Versus SCSIPeripheralsDriverKit: Develop your driver by subclassing IOUserSCSIPeripheralDeviceType00 or IOUserSCSIPeripheralDeviceType05, depending on whether your device works with SCSI Block Commands (SBC) or SCSI Multimedia Commands (SMC), respectively. In your subclass, override all methods the framework declares as pure virtual. The reason these differences exist actually comes from the relationship and interactions between the DEXT families. Case in point, PCIDriverKit doesn't require a specific subclass because it wants SCSIControllerDriverKit DEXTs to be able to directly load "above" it. Note that the common mistake many developers make is leaving "IOUserService" in place when they should have specified a family-specific subclass (case 2 above). This is an undocumented implementation detail, but if there is a mismatch between your DEXT driver ("IOUserSCSIPeripheralDeviceType00") and your kernel driver ("IOUserService"), you end up trying to call unimplemented kernel methods. When a method is "missing" like that, the codegen system ends up handling that by returning kIOReturnUnsupported. One special case here is the "IOUserResources" provider. This class is the DEXT equivalent of "IOResources" in the kernel. In both cases, these classes exist as an attachment point for objects which don't otherwise have a provider. It's specifically used by the sample "Communicating between a DriverKit extension and a client app" to allow that sample to load on all hardware but is not something the vast majority of DEXT will use. Following on from that point, most DEXT should NOT include "IOMatchCategory". Quoting IOKit fundamentals: "Important: Any driver that declares IOResources as the value of its IOProviderClass key must also include in its personality the IOMatchCategory key and a private match category value. This prevents the driver from matching exclusively on the IOResources nub and thereby preventing other drivers from matching on it. It also prevents the driver from having to compete with all other drivers that need to match on IOResources. The value of the IOMatchCategory property should be identical to the value of the driver's IOClass property, which is the driver’s class name in reverse-DNS notation with underbars instead of dots, such as com_MyCompany_driver_MyDriver." The critical point here is that including IOMatchCategory does this: "This prevents the driver from matching exclusively on the IOResources nub and thereby preventing other drivers from matching on it." The problem here is that this is actually the exceptional case. For a typical DEXT, including IOMatchCategory means that a system driver will load "beside" their DEXT, then open the provider blocking DEXT access and breaking the DEXT. DEXT Launching The key point here is that the entire process above is the standard IOKit loading process used by all KEXT. Once that process finishes, what actually happens next is the DEXT-specific part of this process: IOUserServerName-> This key is the bundle ID of your DEXT, which the system uses to find your DEXT target. IOUserClass-> This is the name of the class the system instantiates after launching your DEXT. Note that this directly mimics how IOKit loading works. Keep in mind that the second, DEXT-specific, half of this process is the first point your actual code becomes relevant. Any issue before that point will ONLY be visible through kernel logging or possibly the IORegistry. __ Kevin Elliott DTS Engineer, CoreOS/Hardware
0
0
182
22h
Migrating away from SMJobBless
I have migrated my code to use SMAppService but am running into trouble deleting the old SMJobBless launchd registration using launchd remove. I am invoking this from a root shell when I detect the daemon and associated plist still exist, then also deleting those files. The remove seems to work (i.e. no errors returned) but launchd list shows the service is registered, with a status code of 28 I am using the same label for SMAppService as previously and suspect this is the reason for the problem. However, I am reluctant to change the label as there will a lot of code changes to do this. If I quit my application, disable the background job in System Settings and run sudo launchd remove in the Terminal then it is removed and my application runs as expected once the background job is re-enabled. Alternatively, a reboot seems to get things going. Any suggestions on to how I could do this more effectively welcome.
2
0
36
23h
CloudKit Sync Stalls During Initial Large Data Hydration on New Device (SwiftData Local-First Architecture)
Hi everyone, I’m facing an issue with CloudKit sync getting stuck during initial device migration in my SwiftData-based app. The app follows a local-first architecture using SwiftData + CloudKit sync, and works correctly for: ✔ Incremental sync ✔ Bi-directional updates ✔ Small datasets However, when onboarding a new device with large historical data, sync becomes extremely slow or appears stuck. Even after two hours data is not fully synced. ~6900 Transactions 🚨 Problem When installing the app on a new iPhone and enabling iCloud sync: • Initial hydration starts • A small amount of data syncs • Then sync stalls indefinitely Observed behaviour: • iPhone → Mac sync works (new changes sync back) • Mac → iPhone large historical migration gets stuck • Reinstalling app / clearing container does not resolve issue • Sync never completes full migration This gives the impression that: CloudKit is trickling data but not progressing after a certain threshold. The architecture is: • SwiftData local store • Manual CloudKit sync layer • Local-first persistence • Background push/pull sync So I understand: ✔ Conflict resolution is custom ✔ Initial import may not be optimized by default But I expected CloudKit to eventually deliver all records. Instead, the new device remains permanently in a “partial state”. ⸻ 🔍 Observations • No fatal CloudKit errors • No rate-limit errors • No quota issues • iCloud is available • Sync state remains “Ready” • Hydration remains “mostlyReady” Meaning: CloudKit does not report failure — but data transfer halts. ⸻ 🤔 Questions Would appreciate guidance on: Is CloudKit designed to support large initial dataset migration via manual sync layers? Or is this a known limitation vs NSPersistentCloudKitContainer? ⸻ Does CloudKit internally throttle historical record fetches? Could it silently stall without error when record volume is high? ⸻ Is there any recommended strategy for: • Bulk initial migration • Progressive hydration • Forcing forward sync progress ⸻ Should initial migration be handled outside CloudKit (e.g. via file transfer / backup restore) before enabling sync? ⸻ 🎯 Goal I want to support: • Large historical onboarding • Multi-device sync • User-visible progress Without forcing migration to Core Data. ⸻ 🙏 Any advice on: • Best practices • Debugging approach • CloudKit behavior in such scenarios would be greatly appreciated. Thank you!
1
0
71
23h
Questions about DeclaredAgeRange's isEligibleForAgeFeatures instance variable
Our team is in the process of updating our apps to comply with Texas's new state law. In order to minimize user confusion and provide the most ideal flow to access the app as possible, we have a few questions we would like answered. Summary of questions: Is isEligibleForAgeFeatures intended to be accurate and accessible before the user has accepted the Age Range permissions prompt? As other US states and/or other countries adopt a similar law going forward, will this instance variable cover those locations? Will the runtime crashes on isEligibleForAgeFeatures and other symbols in the DeclaredAgeRange framework be addressed in a future RC or in the official release? Details and Investigations: With regards to isEligibleForAgeFeatures, our team has noticed that this value is always false before the age range prompt has been accepted. This has been tested on the XCode RC 26.2 (17C48). Assuming the request needs to be accepted first, isEligibleForAgeFeatures does not get updated immediately when the user chooses to share their age range (updated to true, when our sandbox test account is a Texas resident). Only upon subsequent relaunches of the app does this return a value that reflects the sandbox user's location. Is isEligibleForAgeFeatures intended to be accurate and accessible before the user has accepted the Age Range permissions prompt? This leads to our follow-up question to clarify whether isEligibleForAgeFeatures explicitly correlates to a user in an affected legal jurisdiction–if future US states and/or other countries adopt a similar law going forward, will this instance variable cover those locations? Can we also get confirmation about whether the runtime crash on isEligibleForAgeFeatures and other symbols in the DeclaredAgeRange framework will be addressed in a future RC or in the official release? Thank you.
6
12
1.1k
1d