I am trying to port Wine 1.7.13 to modern Cocoa. I am considering running Windows binaries in an XPC service’s process, for security isolation and crash-proofing. However, there is one problem: To the best of my knowledge, XPC services are singletons. Only one XPC service process is allowed to be running at a time. This is a problem because, if I use threads to enable multiple Windows binaries to run at once, a segfault or other hard crash in one Windows binary would cause all the other binaries to crash with it.
As mentioned here, it is generally understood that the above assertion is true. If that is so, it would seem that I cannot implement this sort of isolation within a single XPC service process.
My other alternative is to use sandbox inheritance (having the GUI application fork and using more traditional IPC to have the Windows processes talk to each other) instead of an XPC service. What are the pros and cons of using that instead of an XPC service? I understand that processes that inherit their parent’s sandbox does not get to have its own entitlements. What other drawbacks are there?
I also understand that Apple discourages the use of sandbox inheritance in favor of XPC, but it is still an available design decision. They must have kept it around for a reason. Would a sandboxed Mac App Store app be able to use sandbox inheritance in this fashion?
I am going through the same decision. I had my heart set on XPC services, but upon discovering that there would be a single XPC Service with multiple connections, I cannot use them (my XPC Service will use plug-ins provided by third-parties so I want to keep them apart, and also the XPC Service will use libraries that might not clean-up properly, so I want to be able to dispose of them while keeping the UI stable - well I shouldn't have to justify this - I want one-process-per-job and that's that).
I am considering the normal sub-process model using posix_spawn()
(I think this behaves better than fork()
WRT to Sandboxing), CocoaAsyncSocket for the comms. I am going to see if I can replace the use of TCP/IP in CocoaAsynSocket with UNIX sockets to speed-up up comms (with the intent of contributing it back to the project if this works out). (UPDATE: this has already been done, some time ago by github user @jdiehl. See his socketUN
branch and the discussion in issue #88 of the upstream repo).
For data marshalling I will use Google Protocol Buffers (UPDATE #2: Nope; not worth the hassle when NSKeyedArchiver
and NSKeyedUnarchiver
provide everything required out-of-the box. They may not provide data as packed as Google Protocol Buffers, but they 1) Don't require writing and maintaining, 2) Allow any class to participate by implementing the NSCoding
protocol, and 3) Don't have to solve the issue of cross-platform data exchange.
The only possible disadvantage I can see is I don't know if file bookmarks can be passed to the subprocess and used (i.e. the UI opens a file or has a file dragged to it and wants to give access to the file to the worker process). I will update this answer with whatever I learn. (FINAL UPDATE: Passing the URL bookmark across the UNIX domain socket works fine, and the bookmark doesn't even need to be a security-scoped bookmark for this to work. There are no more impediments to this alternative to XPC).
Your assertion is incorrect about sub-processes not having their own entitlements; they do and are embedded into the executable and it must have "inherits sandbox" set for the sub-process to work correctly.
And the end-of-the-day the one-xpc-service-per-app is a show stopper so you have no choice but to find an alternative.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With