Sharing Core Data between Network Extension and the containing application (MacOs)

I am attempting to share Core Data between a Network Extension and the containing application on MacOs. The Network Extension and containing application both have the same AppGroup entitlement and I use the following to get the URL for the storage:

let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "my-group-name")

For the containing application, the resulting URL is of the form:

/Users/***/Library/Group Containers/my-group-name

But for the Network Extension, the resulting URL is different:

/private/var/root/Library/Group Containers/my-group-name

Both the Network Extension and containing application can access their respective Core Data stores, but, of course, they are not shared since the URLs are different.

What am I missing? How is Core Data supposed to be shared between a Network Extension and the containing application?

And, if it matters, I am creating a DNSProxy type extension.

Answered by DTS Engineer in 721471022

And, if it matters, I am creating a DNSProxy type extension.

That does matter. On macOS a DNS proxy provider is always packaged as a system extension and that means it runs as root. A shared container only works between two processes running as the same user. Given that your container app is running as some normal user and the provider is running as root, that can’t possibly work.

My general advice on this front is that you manage this state in your provider and then have the app get and modify the state in the provider via XPC.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Accepted Answer

And, if it matters, I am creating a DNSProxy type extension.

That does matter. On macOS a DNS proxy provider is always packaged as a system extension and that means it runs as root. A shared container only works between two processes running as the same user. Given that your container app is running as some normal user and the provider is running as root, that can’t possibly work.

My general advice on this front is that you manage this state in your provider and then have the app get and modify the state in the provider via XPC.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

That makes sense. A normal user process may access /Users/***/Library/... while a root process will access /private/var/root/Library/.... No sharing that way.

You suggest XPC as the IPC mechanism. Is there any reason I should avoid SwiftNIO? I was able to spin up a quick example that embedded an echo server in the Network Extension and am able to successfully communicate with it. Just want to make sure SwiftNIO is a reasonable approach before going too far down that path.

You suggest XPC as the IPC mechanism. Is there any reason I should avoid SwiftNIO? I was able to spin up a quick example that embedded an echo server in the Network Extension and am able to successfully communicate with it. Just want to make sure SwiftNIO is a reasonable approach before going too far down that path.

Do you need a full HTTP server in the process as opposed to using XPC as Quinn suggested? Using XPC seems like a far simpler approach.

I plan to use JSON with simple newline framing for the communications. I think this can implemented using SwiftNIO with minimal effort and limited baggage since it is a low-level library. Of course, you can implement a fully-fledged HTTP server using SwiftNIO, but that would not be my approach.

Is there any reason I should avoid SwiftNIO?

*shrug* I think that XPC would be much easier but there’s nothing fundamentally wrong with using TCP (or maybe you’re suggesting a Unix domain socket?) for this.

The one thing to watch out for is security. Even if you use a Unix domain socket, so there’s no possibility of connections coming in from other machines, you still need to make sure that the client is correctly authorised. XPC has better facilities for this than Unix domain sockets [1].

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Although LOCAL_PEERTOKEN isn’t a terrible choice.

Sharing Core Data between Network Extension and the containing application (MacOs)
 
 
Q