We've got a non-sandboxed app with a built-in daemon that does some root-privileged things for us on occasion. We're using the newest SMAppService APIs, using NSXPCConnections for communications, and generally things work as expected. The daemon is set up to terminate when the parent app terminates.
Our app also has (and uses the daemon for) a self-update feature. Once the new app is downloaded, the daemon takes over, replaces the app in-place, terminates the old app and launches the new one.
However, after this update, the daemon no longer works.
Any other build & launch of the app will silently fail when trying to talk to the daemon. The XPC connection can be constructed as usual, no errors, the process goes along like it should app-side, but the daemon never actually launches and never responds.
I can imagine there could be a few rules being broken here with the self-update and the built-in daemon, but what would they be and how can we work within the rules?
XPC
RSS for tagXPC is a a low-level (libSystem) interprocess communication mechanism that is based on serialized property lists.
Posts under XPC tag
57 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Let's image that someone wants to use a background service to keep track of FSEvents activity, at the file level (a firehose, some might say).
I choose this example, to indicate the volume and rate of data transmission in question. I'm not creating a front-end for FSEvents data, but my background service may generate data at a similar pace. The service runs off of user defined document/s that specify the FSEvent background filtering to be applied. Those that match get stored into a database. But filters can match on almost all the data being emitted by FSEvents.
The user decides to check on the service's activity and database writes by launching a GUI that sends requests to the background service using XPC. So the GUI can request historic data from a database, but also get a real-time view of what FS events the service is busy filtering.
So it's a client-server approach, that's concerned with monitoring an event stream over XPC. I understand XPC is a request/response mechanism, and I might look into using a reverse connection here, but my main concern is one of performance. Is XPC capable of coping with such a high volume of data transmision? Could it cope with 1000s of rows of table data updates per second sent to a GUI frontend?
I know there are streaming protocol options that involve a TCP connection, but I really want to stay away from opening sockets.
Hello,
I use setCodeSigningRequirement: in sandboxed XPCService and it seems that no matter what I always get errSecCSNoSuchCode[1] when the app is signed with development certificate. The same application signed with DeveloperID is fine.
I use following CSR for development signed builds.
identifier com.example.app and anchor apple generic
and certificate 1[field.1.2.840.113635.100.6.2.1] exists
and certificate leaf[field.1.2.840.113635.100.6.1.12] exists
But also tried to simplify to identifier com.example.app or just true.
If I validated the CSR with codesign -R I get "explicit requirement satisfied".
I spotted this log line:
Sandbox: com.example.app(67058) deny(1) file-read-data /Users/(...)/example-app/build/arm64-mac/src/mac/app/Debug/Example App.app/Contents/MacOS/ExampleApp
So I disabled the sandbox for XPCService and now everything works. But then why the DeveloperID signed build works with XPCService sandboxed? ...or does it really? :)
Just for completeness the CSR which I use in production build are:
identifier com.example.app and anchor apple generic
and certificate 1[field.1.2.840.113635.100.6.2.6] exists
and certificate leaf[field.1.2.840.113635.100.6.1.13] exists
and certificate leaf[subject.OU] = EXAMPLE
Hello,
The man page for xpcservices.plist states that:
Services embedded in an application bundle will only be visible to the containing application (...)
What exactly "visible" means? Doest that mean that there is a mechanism to prevent other programs than the embedding application to access the XPCService's mach port or it just means that the XPCService is not listed (e.g. launchctl list) and if attacker can guess the mach port they can access it?
I'm asking to understand if there is a security gain using the -[NSXPCConnection setCodeSigningRequirement:] for embedded XPCServices.
How do you send an NSURL representing a new file, as returned from an NSSavePanel, to an XPC service such that the service is granted permission to create the file?
I can successfully pass an NSURL to the XPC process if the NSURL represents an existing file. This is documented in Apple's Documentation:
Share file access between processes with URL bookmarks
This involves creating bookmark date while passing 0 in as the options. However, if you try to create bookmark data for an NSURL that represents a file that is not yet created, you do not get any bookmark data back and an error is returned instead:
Error Domain=NSCocoaErrorDomain Code=260
"The file couldn’t be opened because it doesn’t exist."
Simply passing the file path to the XPC process, by way of:
xpc_dictionary_set_string(message, "file_path", url.fileSystemRepresentation);
Does not grant the XPC create/write permissions. Is there an API or trick I'm missing?
Note that the user should be allowed to save and create new files anywhere of their choosing, thus restricting URLs to only those within a group or container shared between the app and service isn't really viable.
Using the latest of everything on macOS with the xpc_session API...
(Updated)
See replies below.
2024-06-04 15:17:59.618853+0100 ProxyAgent[20233:29237510] [xpc.exceptions] <NSXPCConnection: 0x60000331cb40> connection from pid 20227 on anonymousListener or serviceListener: Exception caught during decoding of received selector newFlowWithIdentifier:to:type:metadata:socket:, dropping incoming message.
Exception: Exception while decoding argument 4 (#6 of invocation):
<NSInvocation: 0x600001778780>
return value: {v} void
target: {@} 0x0
selector: {:} null
argument 2: {@} 0x6000017787c0
argument 3: {@} 0x60000002d170
argument 4: {q} 1
argument 5: {@} 0x600001746600
argument 6: {@} 0x0
Exception: decodeObjectForKey: Object of class "NSFileHandle" returned nil from -initWithCoder: while being decoded for key <no key>
The extension is in Swift; the recipient is in ObjC (wheeeeee).
Based on the extension's logging, the FileHandle is not nil.
I am trying to pass a FileHandle based on a socketpair up to the user-land code. The sockets are created happily.
Any ideas what's going wrong here?
hi all.
I subscribe the notify write event, every time I recieve a notify write event message i will send log data and reply block(didn't do nothing) with async method to host app(Objc XPC API).host app will reply immediately once it recieves data. after a while my sysext crashed, then I checked system log find the log below.
launchd: exited with exit reason (namespace: 30 code: 0xc40000000004aaaa) - (unknown reason)
is it because of exceeding the maximum limit of xpc's block queue length, or too many memory allocation, or...
by the way, host app didn't crash.
how this happened exactly? how could i solve it?
Hi :wave:
I started a new project to experiment with EndpointSecurity framework.
It seems to have been worked, but when I try to add XPC I face some troubles.
I am not able to send XPC message from my app to my system extension.
No runtime error, but when I'm inspecting logs:
That correspond to this code: https://github.com/tony-go/TestES/blob/main/Extension/main.swift#L21-L30
Full project: https://github.com/tony-go/TestES/
I thought at first that it could come from a missing @objc somehere but it does not seems ...
I also wonder why I cannot catch this error at runtime ?
I'm using XPC to do IPC with an agent service.
I use NSXPCConnection initWithMachServiceName to create the connection and active it.
Then I get the agent service remote object proxy with method remoteObjectProxyWithErrorHandler. But when the agent service unloaded, I can also get the remote proxy without any error.
Is there anyway to check XPCConnection really connect to a XPC server?
Hi everyone,
first-time caller, long-ti... wait, no, I just got here. :)
I am relatively new to all things Apple, so apologies in advance if it takes me a few goes to properly explain things.
We have a framework, which includes an API, an XPC service, etc, and we have a device driver. We also have some sample apps that use the framework, and if they have the app sandbox capability, then we expect them to use the XPC Service instead of accessing our driver directly. This works fine on Monterey and presumably has worked fine on all previous versions of MacOS.
Something seems to have changed on Ventura, and we don't understand what.
When we build the same app on Ventura, it appears to be in the sandbox (according to the Sandbox column in Activity Monitor), but in the Console there is this line (twice):
default <time> <OurAppName> Revoking sandbox extension; key = 0
Which we suspect is linked to the fact that the app then does not use the XPC Service, and instead accesses the driver directly, much to our surprise.
Software built on developer's machines is "Automatically managed" and "Signed to Run Locally" in case that matters.
Do we need to change our code to support Ventura and onward? Or is it a bizarre bug?
Oh, I should say that I'm running the latest version of Ventura (13.6.7 as of writing) but not the latest Xcode (14.2 (14C18)) and CLI tools... can't remember how to find that version... Apple clang version 14.0.0 (clang-1400.0.29.202).
Any help would be appreciated, thanks.
Jeremy
I create a camera extension and App can push video data to camera extension with sinkStream. I want to monitor the number of clients connected to the camera extension and close the app's push stream when the number of connected client is zero.
I am attempting to install and utilize an agent using the new(ish) SMAppService API with an existing app. The agent appears to install (no error is returned), but when I try to start the agent from Terminal, I get the following in the launchd.log:
2024-04-22 09:57:27.469039 (gui/502/com.redacted.service.agent) : internal event: WILL_SPAWN, code = 0
2024-04-22 09:57:27.469080 (gui/502/com.redacted.service.agent) : service state: spawn scheduled
2024-04-22 09:57:27.469081 (gui/502/com.redacted.service.agent) : service state: spawning
2024-04-22 09:57:27.469100 (gui/502/com.redacted.service.agent) : launching: one-shot
2024-04-22 09:57:27.469105 (gui/502/com.redacted.service.agent) : Allowing non-reentrant proxy for resolving path
2024-04-22 09:57:27.469947 (gui/502/com.redacted.service.agent [71866]) : xpcproxy spawned with pid 71866
2024-04-22 09:57:27.469960 (gui/502/com.redacted.service.agent [71866]) : internal event: SPAWNED, code = 0
2024-04-22 09:57:27.469964 (gui/502/com.redacted.service.agent [71866]) : service state: xpcproxy
2024-04-22 09:57:27.469997 (gui/502/com.redacted.service.agent [71866]) : internal event: SOURCE_ATTACH, code = 0
2024-04-22 09:57:27.506283 (gui/502/com.redacted.service.agent [71866]) : Service could not initialize: posix_spawn(/Users/chrisf/Library/Developer/Xcode/DerivedData/Redacted-gttupgdyakodzddurpavhmscwabs/Build/Products/Debug/Redacted App.app/Contents/MacOS/Service Agent.app), error 0xd - Permission denied
2024-04-22 09:57:27.506306 (gui/502/com.redacted.service.agent [71866]) : initialization failure: 23E224: xpcproxy + 31420 [1098][A7EF179C-FBCC-349E-A7D2-09B2F1408413]: 0xd
2024-04-22 09:57:27.506309 (gui/502/com.redacted.service.agent [71866]) : internal event: INIT, code = 13
2024-04-22 09:57:27.506313 (gui/502/com.redacted.service.agent [71866]) : job state = spawn failed
2024-04-22 09:57:27.507148 (gui/502/com.redacted.service.agent [71866]) : xpcproxy exited due to exit(78)
2024-04-22 09:57:27.507153 (gui/502/com.redacted.service.agent [71866]) : exited due to exit(78)
2024-04-22 09:57:27.507162 (gui/502/com.redacted.service.agent [71866]) : already handled failed init, ignoring
2024-04-22 09:57:27.507170 (gui/502/com.redacted.service.agent [71866]) : service state: exited
2024-04-22 09:57:27.507186 (gui/502/com.redacted.service.agent [71866]) : internal event: EXITED, code = 0
(tldr: error 0xd - Permission denied)
I'd also be curious how we are expected to launch agents once registered with SMAppService. Is it sufficient simply to make an XPC call to an exposed method?
Thanks!
I noticed a problem while writing a program using XPC on macOS.
When I write it in the form of a closure that receives the result of an XPC call, I can't receive it forever.
I add an XPC target in Xcode, the sample code is used in the pass closure format, but can't I use closure passing with XPC?
My Environment:
Xcode 15.3
macOS 14.4.1
caller (closure version)
struct ContentView: View {
@State var callbackResult: String = "Waiting…"
var body: some View {
Form {
Section("Run XPC Call with no argument and no return value using callback") {
Button("Run…") {
callbackResult = "Running…"
let service = NSXPCConnection(serviceName: "net.mtgto.example-nsxpc-throws-error.ExampleXpc")
service.remoteObjectInterface = NSXPCInterface(with: ExampleXpcProtocol.self)
service.activate()
guard let proxy = service.remoteObjectProxy as? any ExampleXpcProtocol else { return }
defer {
service.invalidate()
}
proxy.performCallback {
callbackResult = "Done"
}
}
Text(callbackResult)
...
}
}
}
callee (closure version)
@objc protocol ExampleXpcProtocol {
func performCallback(with reply: @escaping () -> Void)
}
class ExampleXpc: NSObject, ExampleXpcProtocol {
@objc func performCallback(with reply: @escaping () -> Void) {
reply()
}
}
I found this problem can be solved by receiving asynchronous using Swift Concurrency.
caller (async version)
struct ContentView: View {
@State var callbackResult: String = "Waiting…"
var body: some View {
Form {
Section("Run XPC Call with no argument and no return value using callback") {
Button("Run…") {
simpleAsyncResult = "Running…"
Task {
let service = NSXPCConnection(serviceName: "net.mtgto.example-nsxpc-throws-error.ExampleXpc")
service.remoteObjectInterface = NSXPCInterface(with: ExampleXpcProtocol.self)
service.activate()
guard let proxy = service.remoteObjectProxy as? any ExampleXpcProtocol else { return }
defer {
service.invalidate()
}
await proxy.performNothingAsync()
simpleAsyncResult = "DONE"
}
Text(simpleAsyncResult)
...
}
}
}
callee (async version)
@objc protocol ExampleXpcProtocol {
func performNothingAsync() async
}
class ExampleXpc: NSObject, ExampleXpcProtocol {
@objc func performNothingAsync() async {}
}
To simplify matters, I write source code that omits the arguments and return value, but it is not also invoked by using callback style.
All sample codes are available in
https://github.com/mtgto/example-nsxpc-throws-error
Hello Apple Developer Community,
I'm encountering an issue with my macOS application where I'm receiving the following error message:
Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.FxPlugTestXPC was invalidated: failed at lookup with error 159 - Sandbox restriction." UserInfo={NSDebugDescription=The connection to service named com.FxPlugTestXPC was invalidated: failed at lookup with error 159 - Sandbox restriction.}
This error occurs when my application tries to establish a connection to an XPC service named com.FxPlugTestXPC. It appears to be related to a sandbox restriction, but I'm unsure how to resolve it.
I've checked the sandboxing entitlements and ensured that the necessary permissions are in place. However, the issue persists.
Has anyone encountered a similar error before? If so, could you please provide guidance on how to troubleshoot and resolve this issue?
Any help or insights would be greatly appreciated.
Thank you.
this is some photos about my entitlements :
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?
I've been experimenting with the new low-level Swift API for XPC (XPCSession and XPCListener). The ability to send and receive Codable messages is an appealing alternative to making an @objc protocol in order to use NSXPCConnection from Swift — I can easily create an enum type whose cases map onto the protocol's methods.
But our current XPC code validates the incoming connection using techniques similar to those described in Quinn's "Apple Recommended" response to the "Validating Signature Of XPC Process" thread. I haven't been able to determine how to do this with XPCListener; neither the documentation nor the Swift interface have yielded any insight.
The Creating XPC Services article suggests using Xcode's XPC Service template, which contains this code:
let listener = try XPCListener(service: serviceName) { request in
request.accept { message in
performCalculation(with: message)
}
}
The apparent intent is to inspect the incoming request and decide whether to accept it or reject it, but there aren't any properties on IncomingSessionRequest that would allow the service to make that decision. Ideally, there would be a way to evaluate a code signing requirement, or at least obtain the audit token of the requesting process.
(I did notice that a function xpc_listener_set_peer_code_signing_requirement was added in macOS 14.4, but it takes an xpc_listener_t argument and I can't tell whether XPCListener is bridged to that type.)
Am I missing something obvious, or is there a gap in the functionality of XPCListener and IncomingSessionRequest?
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!
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
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)
}