XPC is a a low-level (libSystem) interprocess communication mechanism that is based on serialized property lists.

Posts under XPC tag

54 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Unsandboxed XPCService launches sandboxed child processes
I have an application, it has main process and some child processes. As we want those child processes to have their own minimum sandbox privilege, not inheriting from parent process, we plan to use XPCService which uses a NSTask to launch those child processes, so those child processes can have its own sandbox privilege. We plan to deliver the application to Mac App Store, so process mode is: the sandboxed main process builds connections to the unsandboxed XPCService, the unsandboxed XPCService launch those sandboxed child processes. Can this process mode pass the Mac App Store rules? I see, there is a rule that all processes must be sandboxed, including XPCService. But I tested locally, the Application downloaded from Mac apple store also launches unsandboxed XPCService, like OneDrive. Do you have any suggestions for my application scenario, sandboxed child processes having its own privilege not inheriting from parent?
2
0
416
Apr ’24
Unable to get function reply back from Mach XPC command line daemon
We are working on a command line daemon (started with launchd) for a UI to communicate with using XPC. The functions we have been using so far work correctly, but they only take arguments and return void. We wanted to add a function with a simple reply block to see if the daemon is running or not, and we may need to get data back in the future. But it is not working. For example, this is working: if let proxy = connectionToService.remoteObjectProxyWithErrorHandler({ error in print(error.localizedDescription) }) as? TheDaemonProtocol { proxy.doStuff("Test string") } But this returns an error "Couldn’t communicate with a helper application." if let proxy = connectionToService.remoteObjectProxyWithErrorHandler({ error in print(error.localizedDescription) }) as? TheDaemonProtocol { proxy.isUp { reply in print("reply: \(reply)") } } isUp() is coded to only return true for now. @objc func isUp(reply: @escaping (Bool) -> Void) { reply(true) } TIA for any help!
4
0
371
Apr ’24
Compile XPC service with a different architecture than the client
I'm working on a macOS application that deals with a few external dependencies that can only be compiled for intel (x86_64) but I want the app to run natively on both arm and x86_64. One idea I have been playing with is to move the x86_64 dependencies to an xpc service compiled only as x86_64 and use the service only the intel machine. However, I can't figure out how to setup my project to compile everything at once... Any ideas? Is this even possible? If not, I'm open to suggestions... Thanks
2
0
358
Mar ’24
XPC Resources
XPC is the preferred inter-process communication (IPC) mechanism on Apple platforms. XPC has three APIs: The high-level NSXPCConnection API, for Objective-C and Swift The low-level Swift API, introduced with macOS 14 The low-level C API, which, while callable from all languages, works best with C-based languages General: DevForums tag: XPC Creating XPC services documentation NSXPCConnection class documentation Low-level API documentation XPC has extensive man pages — For the low-level API, start with the xpc man page; this is the original source for the XPC C API documentation and still contains titbits that you can’t find elsewhere. Also read the xpcservice.plist man page, which documents the property list format used by XPC services. Daemons and Services Programming Guide archived documentation WWDC 2012 Session 241 Cocoa Interprocess Communication with XPC — This is no longer available from the Apple Developer website )-: Technote 2083 Daemons and Agents — It hasn’t been updated in… well… decades, but it’s still remarkably relevant. TN3113 Testing and Debugging XPC Code With an Anonymous Listener XPC and App-to-App Communication DevForums post Validating Signature Of XPC Process DevForums post Related tags include: Inter-process communication, for other IPC mechanisms Service Management, for installing and uninstalling Service Management login items, launchd agents, and launchd daemons Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
0
0
1.6k
Mar ’24
Validating Signature Of XPC Process
Quinn, you've often suggested that to validate the other side of an XPC connection, we should use the audit token. But that's not available from the XPC object, whereas the PID is. So everyone uses the PID. While looking for something completely unrelated, I found this in the SecCode.h file OSStatus SecCodeCreateWithXPCMessage(xpc_object_t message, SecCSFlags flags, SecCodeRef * __nonnull CF_RETURNS_RETAINED target); Would this be the preferred way to do this now? At least from 11.0 and up. Like I said, I was looking for something completely unrelated and found this and don't have the cycles right now to try it. But it looks promising from the description and I wanted to check in with you about it in case you can say yes or no before I get a chance to test it. Thanks
8
0
5.6k
Mar ’24
Swift Process with Psuedo Terminal (PTY)
Hi! I'm looking for some insight and guidance on using the Foundation.Process type with a PTY (Psuedo Terminal) so that the subprocess can accept input and behave as if it was running via a terminal. The reason for needing a PTY is that for programs like ssh or in my case (xcodes) which ask for user input including passwords, running these via Foundation.Process does not display the prompts to the user as the output is usually buffered (this works fine in the Xcode debugger console but when running via a real terminal that is buffered the prompts are never displayed in the terminal) Looking at other threads it seems like correct approach here is create a PTY and use the filehandles to attach to the Process. While I've got this to work to the point where prompts are now shown, I cant seem to figure out how to pass input back to the process as these are being controlled by the PTY. Here is my Process setup: let process = Process() // Setup the process with path, args, etc... // Setup the PTY handles var parentDescriptor: Int32 = 0 var childDescriptor: Int32 = 0 guard Darwin.openpty(&parentDescriptor, &childDescriptor, nil, nil, nil) != -1 else {   fatalError("Failed to spawn PTY") } parentHandle = FileHandle(fileDescriptor: parentDescriptor, closeOnDealloc: true) childHandle = FileHandle(fileDescriptor: childDescriptor, closeOnDealloc: true) process.standardInput = childHandle process.standardOutput = childHandle process.standardError = childHandle With this setup I then read the parent handle and output any result it gets (such as the input prompts): parentHandle?.readabilityHandler = { handle in   guard let line = String(data: handle.availableData, encoding: .utf8), !line.isEmpty else {     return   }   logger.notice("\(line)") } When process.run() is executed the program runs and I can see it asks for Apple ID: input in my terminal, however, when typing input into the terminal the process does not seem to react to this input. I've tried forwarding the FileHandle.standardInput: FileHandle.standardInput.readabilityHandler = { handle in   parentHandle?.write(handle.availableData) } But this doesn't seem to work either. What is the recommended way to setup a PTY with Foundation.Process for executing arbitrary programs and having them behave as if they were being run in a terminal context? Most of the resources I found online are about other languages and I'd like to stick with Foundation.Process vs. doing anything custom in C/C++ if possible as it just makes it easier to reason about / maintain. The resources for Swift on this topic are very lacking and I've checked out some open source projects that claim to do this but most require manually sending input to the PTY handle vs. accepting them from the user in a terminal. Any insight / help is very much appreciated!
9
0
2.9k
Mar ’24
Setup LaunchAgent in Xcode
Hi there :) I try to put an Xcode project in place within a LaunchAgent. The ultimate goal is to have an "application" with two component: macOS application with just an basic UI all the logic happens in a LaunchAgent that runs on background and is launch at startup. The macOS app uses XPC to send messages to the agent that will run either the app is opened or not. I struggled at first having this error (for the agent): An XPC Service cannot be run directly. Then I found using MachServices key in the .plist of the agent fixes the issue, plus: let listener = NSXPCListener.init(machServiceName: "com.tonygo.NetworkMonitorAgent") Then I wonder: Do we have somewhere a documentation about how to setup a LaunchAgent in Xcode I create the plist of the agent on side and run it manually, I could do this in a more automatic way How could I package a macOS applciation that will contains the agent, install it and load the agent? Note: This is mainly for learning and understanding what we could do at each level (XPCService, LaunchAgents, LaunchDaemon, etc.).
23
0
1.6k
Feb ’24
Commission Matter accessory added via Apple Home
Greetings! I've added a Matter accessory via the Apple Home app. In my app, I'm attempting to commission this device and add it to my fabric. However, when I try to open the commissioning window, I receive an error stating, MTRBaseDevice doesn't support openCommissioningWindowWithDiscriminator over XPC. It appears that opening a commissioning window via an XPC connection is not yet supported. Is there another method to commission the device? Can I retrieve the setup payload from the MTRBaseDevice object or the shared MTRDeviceController? Here's the simplified version of my code: var home: HMHome // HMHome received via HMHomeManager var accessory: HMAccessory = home.accessory[0] // my Matter-supported accessory let deviceController = MTRDeviceController.sharedController( withID: home.matterControllerID as NSCopying, xpcConnect: home.matterControllerXPCConnectBlock ) let device = MTRBaseDevice( nodeID: accessory.matterNodeID as NSNumber, controller: deviceController ) device.openCommissioningWindow( withDiscriminator: 0, duration: 900, queue: .main) { payload, error in if let payload { // payload not received } else if let error { // I'm getting here "Error Domain=MTRErrorDomain Code=6 "(null)"" // and "MTRBaseDevice doesn't support openCommissioningWindowWithDiscriminator over XPC" logged in the console print(error) }
0
0
504
Feb ’24
Audio Server Plugin entitlements and communication
I am currently working on planning a multi-component software system that consists of an Audio Server Plugin and an application for user interaction. I have very little experience with IPC/XPC and its performance implications, so I hope I can find a little guidance here. The Audio Server plugin publishes a number of multi-channel output devices on which it should perform computations and pass the result on to a different Core Audio device. My concerns here are: Can the plugin directly access other CoreAudio devices for audio output or is this prohibited by the sandboxing? If it cannot, would relaying the audio data via XPC be a good idea in terms of low latency stability? Can I use metal compute from within the Audio Server plugin? I have not found any information about metal related sandboxing entitlements. I am also concerned about performance implications as above. Regarding the user interface application, I would like to know: If a process that has not been started by launchd can communicate with the Audio Server plugin using XPC. If not, would a user agent instead of an app be a better choice? Or are there other communication channels that would work with sandboxing? Thank you very much! Andreas
0
0
587
Feb ’24
XPC, memory allocation, and much confusion
I asked a similar question last year, and got no responses. I've written a much simpler (no network extension!) case that seems to demonstrate what I'm confused about. Simple app with an XPC service. I have an ObjectiveC class TestObject which has an NSString* and an NSData* (which I never actually use). I have a protocol defined in Swift: @objc protocol XPCTestServiceProtocol { func logData(entry: TestObject) -> Void func logData(entry: TestObject, completion: ((String) -> Void)) } In the Switt XPC service, the code is: class XPCTestService: NSObject, XPCTestServiceProtocol { var totalBytes = 0 var lastName = "" @objc func logData(entry: TestObject) { totalBytes += (entry.data?.count ?? 0) } @objc func logData(entry: TestObject, completion: ((String) -> Void)) { totalBytes += (entry.data?.count ?? 0) completion("Finished") } I've got this code in the ObjC app: id<XPCTestServiceProtocol> proxy = [self.connection remoteObjectProxyWithErrorHandler:^(NSError* error) { self.stopRun = YES; NSLog(@"Proxy got error %@", error); }]; while (self.stopRun == NO) { @synchronized (self) { NSNumber *objNum = [NSNumber numberWithUnsignedLongLong:self.count++]; NSString *objName = [NSString stringWithFormat:@"Object %@", objNum]; TestObject __weak *toWeak = to; #if USE_COMPLETION [proxy logDataWithEntry:to completion:^(NSString *str) { to = nil; }]; #else [proxy logDataWithEntry:to]; #endif } } attached to a start button (and self.stopRun is set by a stop button, this is all super simple). So I run that, start the test, and things start going (122k calls/second it says). According to Activity Monitor, my app is using about 1gbyte after 20 seconds or so. However, if I run it under Instruments' Leaks template... Activity Monitor says it's used only about 60mbytes. (And at the end of the run, Instruments says it's used about 30mbytes.) Now... if I use the completion and a synchronous proxy, then even without Instruments, Activity Monitor says it's 60mbytes or so. Is the memory reported by Activity Monitor real? Or not real?
12
0
797
Feb ’24
Migrating from pkg installer to Service Management
Hello, we are currently working on a plan to migrate our app suite from Developer ID binaries inside a simple pkg installer to macOS app store distribution. The reason we are using an installer is that there are multiple binaries inside that communicate via XPC and we need to install the respective launchd plist in /Library/LaunchDaemons and /Library/LaunchAgents: 1 root daemon 1 agent that has minimal UI and lives in the system menu bar 1 embedded command line utility in user agent 1 embedded FileProvider extension in user agent 1 embedded Action Extension in user agent 1 agent that only does OAuth stuff Looking through Updating helper executables from earlier versions of macOS I can install the root daemon with SMAppService.daemon(plistName:) and the OAuth helper with SMAppService.agent(plistName:). For the main application I only found SMAppService.mainApp which does not accept a property list configuration. Therefore, I have no place to put my MachServices array and so the File Provider extension, the Action Extension, and the embedded command line utility have no way to talk to the user agent. Currently, XPC is used in between these processes: user agent -> root daemon command line utility -> user agent action extension -> user agent file provider extension -> user agent user agent -> file provider extension: that already works through NSFileProviderServicing I know app-to-app communication only works through launchd for security reasons, but these applications are all part of the same app group (except the root daemon obviously). My question is what is the proper way of starting the user agent so XPC from other binaries just work ™️? Any input is much appreciated!
3
0
536
Feb ’24
Using `SecCodeCopyGuestWithAttributes` with auditToken results in `100001 - UNIX[Operation not permitted]`
Hi everyone :) I'm exploring XPC these days; more specifically, I'm trying to establish a connection between a macOS application and an XPC service. I succeeded in establishing the connection, but now I'm trying to verify the incoming connection by using SecCodeCopyGuestWithAttributes, passing it an audit token. But I got the following error: 2024-01-18 10:43:06.805435+0100 DemoService[1627:7118397] [logging-persist] cannot open file at line 46922 of [554764a6e7] 2024-01-18 10:43:06.805452+0100 DemoService[1627:7118397] [logging-persist] os_unix.c:46922: (0) open(/private/var/db/DetachedSignatures) - Undefined error: 0 Cannot get SecCode: 100001 - UNIX[Operation not permitted] Audit token: Optional(32 bytes) The last two lines come from my code: class XPCClientValidator { var secCodeOptional: SecCode? = nil; func identifyGuest(for connection: NSXPCConnection) -> Bool { let auditToken = AuditToken.extractToken(from: connection) let hostSecCode: SecCode? = nil; // This is a way to indicate that the code signing root of trust hould be used as host. let attributes = [ kSecGuestAttributeAudit: auditToken ] as CFDictionary let secFlags = SecCSFlags(rawValue: 0) // Asks a code host to identify the guest given the audit token let status: OSStatus = SecCodeCopyGuestWithAttributes(hostSecCode, attributes, secFlags, &self.secCodeOptional) if (status != errSecSuccess) { let msg = SecCopyErrorMessageString(status, nil)! print("Cannot get SecCode: \(status) - \(msg)") print("Audit token: \(String(describing: auditToken))") return false } guard let _ = secCodeOptional else { NSLog("Couldn't unwrap the secCode") return false } return true } } I saw a few posts on the forum, but nothing helped me to solve this issue. The complete source code is here: https://github.com/tony-go/XPCDemo/tree/secure-xpc Note: If you want to reproduce it, you have to: start the app type a random input click on "uppercase it"
5
0
654
Jan ’24
XPC Rendezvous, com.apple.security.inherit and LaunchAgent
I’m trying to implement XPC Rendezvous like Quinn described in many awesome posts on here but I’m now at a stuck point were I just have no idea. I want to communicate with a Safari extension via XPC and also a helper application which led me to XPC Rendezvous (https://developer.apple.com/forums/thread/715338) because a XPC Service in the Extension is scoped to the container. I then made a Command Line Target and added it like its described here (https://developer.apple.com/documentation/xcode/embedding-a-helper-tool-in-a-sandboxed-app ) and also took the xpc test code and inspiration to set up my launch agent from here (https://developer.apple.com/documentation/servicemanagement/updating_your_app_package_installer_to_use_the_new_service_management_api). This command line tool should do the management for the XPC connections because it’s not in the sandboxed container. The tool sets up the xpc connection like in the sample code directly and not in a XPC Service added via a Target template. It exposes the Mach Service. And that looks like its building fine after some fighting but the service just wont start - I saw it trying in console and after running it in Xcode and finally finding the crash report - it brought me there (https://developer.apple.com/forums/thread/706390) I have Process is not in an inherited sandbox. - and thinking about it, it makes sense because I first thought its just because it ran through Xcode, but its crashing this way also as a LaunchAgent. I mean it does make sense - there is nothing to inherit because it’s spawned by launchd - and that’s what I want isn’t it - to make the Rendezvous? Okay I thought now removing com.apple.security.inherit brings it in its own Sandbox (its needs sandboxing) but this also crashes the process because of the sandbox. Also after adding it to the App Group. What am I missing here or what do I want to accomplish? Do I want to inherit the sandbox? I guess not the helper should have its own. The only difference I see in comparison to SMAppServiceSampleCode is it moves the product in Copy Bundle Resources, and I have a Copy Files Phase with Destination: Executables (Like the other sample code said - and that’s looks “more correct” - and well SMAppServiceSampleCode isn’t sandboxed. I then tried making a new Command Line Target and just added App Sandbox Capability and tried to run this fresh one - and that also crashes. This makes me think I’m just ****** somewhere but I have read now everything I could find. I’m happy to provide any Code or crash logs but I dont know what part is really relevant here, It looks like the LaunchAgent gets installed correctly and wants to run but the sandbox is preventing me. The Bundle Identifier and XPC device name of the helper starts with my teamID (I got that from here https://developer.apple.com/forums/thread/703702) What could I be doing wrong? Thanks a lot! Benjamin
7
0
1k
Dec ’23
IPC between two processes
I am looking for a solution to transfer data between two completely separate processes (not from the same group). I did a lot of research, but the solutions were mostly for processes that are in a group. Is there a method? (It doesn't matter if the app is sandboxed, I can disable it). My goal is to communicate between a bundle(plugin) that is activated on the Mac login page and an XPC service and transfer data from the service to the bundle.
3
0
670
Dec ’23
XPC Connection with Network Extension fails after upgrade
Hi Team, I have a Network Extension application and UI frontend for it. The UI frontend talks to the Network Extension using XPC, as provided by NEMachServiceName. On M2 machine, The application and XPC connection works fine on clean installation. But, when the application is upgraded, the XPC connection keeps failing. Upgrade steps: PreInstall script kills the running processes, both UI and Network Extension Let installation continue PostInstall script to launch the application after installation complete. Following code is successful to the point of resume from UI application NSXPCInterface *exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(IPCUIObject)]; newConnection.exportedInterface = exportedInterface; newConnection.exportedObject = delegate; NSXPCInterface *remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(IPCExtObject)]; newConnection.remoteObjectInterface = remoteObjectInterface; self.currentConnection = newConnection; [newConnection resume]; But it fails to get the object id<IPCExtObject> providerProxy = [self.currentConnection remoteObjectProxyWithErrorHandler:^(NSError *registerError) { }]; Please note, this only fails for M2. For M1, this exact code is running fine. Additionally, if I uninstall the application by dropping it in Trash and then installing the newer version, then too, the application works fine.
2
0
516
Dec ’23
is XPC from app to CMIOExtension possible?
I built an app which hosts a CMIOExtension. The app works, and it can activate the extension. The extension loads in e.g. Photo Booth and shows the expected video (a white horizontal line which moves down the picture). I have a couple of questions about this though. The sample Camera Extension is built with a CMIOExtension dictionary with just one entry, CMIOExtensionMachServiceName which is $(TeamIdentifierPrefix)$(PRODUCT_BUNDLE_IDENTIFIER) This Mach service name won't work though. When attempting to activate the extension, sysextd says that the extensions has an invalid mach service name or is not signed, the value must be prefixed with one of the App Groups in the entitlement. So in order to get the sample extension to activate from my app, I have to change its CMIOExtensionMachServiceName to <my team ID>.com.mycompany.my-app-group.<myextensionname> Is this to be expected? The template CMIOExtension generates its own video using a timer. My app is intended to capture video from a source, filter that video, then feed it to the CMIOExtension, somehow. The template creates an app group called "$(TeamIdentifierPrefix)com.example.app-group", which suggests that it might be possible to use XPC to send frames from the app to the extension. However, I've been unable to do so. I've used NSXPCConnection * connection = [[NSXPCConnection alloc] initWithMachServiceName:, using the CMIOExtensionMachServiceName with no options and with the NSXPCConnectionPrivileged option. I've tried NSXPCConnection * connection = [[NSXPCConnection alloc] initWithServiceName: using the extension's bundle identifier. In all cases when I send the first message I get an error in the remote object proxy's handler: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named <whatever name I try> was invalidated: failed at lookup with error 3 - No such process." According to the "Daemons and Services Programming Guide" an XPC service should have a CFBundlePackageType of XPC!, but a CMIOExtension is of type SYSX. It can't be both. Does the CMIOExtension loading apparatus cook up a synthetic name for the XPC service, and if so, what is it? If none, how is one expected to get pixel buffers into the camera extension?
19
0
6.9k
Dec ’23
Secure XPC service call
I would like to develop a macOS application in Swift. This application will consist of 2 programs: a main program to be run by the user (standard account) and another one that will run with root privileges. The second program will only be invoked to perform privileged tasks. Running the main program under root permanently would be too risky. XPC will be used to trigger calls from the main program to the privileged program. How can I secure the privileged program to ensure that the calling program is indeed my main program and not another unauthorized program?
1
0
477
Dec ’23
libxpc library crash on top of callstack after iOS 16 version
Hi team, We found that the app reported a lot of crash stacks, and the top of the stack had the libxpc library feature, but we could not find the reason. These issues have only emerged since iOS 16 and are growing, can you provide some clues or provide some solutions? Thanks! Crash backtrace can be seen as follows. _ OS Version: 16.6.1 (20G81) Report Version: 104 SDK start time: 2023-09-20 18:42:40 RDM SDK Version: 2.7.27.1 RDM user id : 119902290602 RDM DeviceId: 0DB20076-F323-468F-9EEC-080B77A00E05 RDM APP KEY: 7c35edbf90 Last Exception : 0 libxpc.dylib 0x000000020a019e98 __xpc_dictionary_insert + 96 1 libxpc.dylib 0x000000020a019e84 __xpc_dictionary_insert + 76 2 libxpc.dylib 0x000000020a01b944 __xpc_dictionary_deserialize_apply + 68 3 libxpc.dylib 0x000000020a01b8cc __xpc_dictionary_apply_wire_f + 136 4 libxpc.dylib 0x000000020a018da4 __xpc_dictionary_deserialize + 108 5 libxpc.dylib 0x000000020a00cdf4 __xpc_array_deserialize + 204 6 libxpc.dylib 0x000000020a01b9ec __xpc_dictionary_unpack_value + 120 7 libxpc.dylib 0x000000020a01bbf0 __xpc_dictionary_unpack_value_and_vend + 28 8 libxpc.dylib 0x000000020a01a4c4 __xpc_dictionary_look_up + 156 9 libxpc.dylib 0x000000020a01b094 _xpc_dictionary_get_array + 20 10 libdns_services.dylib 0x000000020a0b9a28 ____dnssd_client_connection_block_invoke_2 + 320 11 libxpc.dylib 0x000000020a015af0 __xpc_connection_call_event_handler + 152 12 libxpc.dylib 0x000000020a015f20 __xpc_connection_mach_event + 992 13 libdispatch.dylib 0x00000001b1657f6c __dispatch_client_callout4 + 20 14 libdispatch.dylib 0x00000001b16746ec __dispatch_mach_msg_invoke + 468 15 libdispatch.dylib 0x00000001b165f40c __dispatch_lane_serial_drain + 372 16 libdispatch.dylib 0x00000001b1675438 __dispatch_mach_invoke + 448 17 libdispatch.dylib 0x00000001b165f40c __dispatch_lane_serial_drain + 372 18 libdispatch.dylib 0x00000001b16600a4 __dispatch_lane_invoke + 384 19 libdispatch.dylib 0x00000001b166acdc __dispatch_workloop_worker_thread + 648 20 libsystem_pthread.dylib 0x0000000209fc1ddc __pthread_wqthread + 288 Exception Type: SIGSEGV SEGV_ACCERR Exception Codes: fault addr: 0x0000000000000036 Crashed Thread: 7 _
14
0
1.7k
Nov ’23