network extension, app groups, unix domain socket

Hi to all.



I am developing network extension and have several issues that I faced and have no idea how to solve.



So:

1. there is sandboxed application that can install/unintall own network extension;

2. there is App Group(https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups?language=objc), sandboxed application and appropriate network extension are included into group via owns entitlement files;

3. App group registered manualy on https://developer.apple.com/account/resources/identifiers/list/applicationGroup, the same identifier is used in appropriate entitlement files. Identifier on site looks like "group.TEAM_ID.com.company.app-group". Identifier in entitlement looks like "TEAM_ID.com.company.app-group", i.e. without precending "group";

4. It is required to use unix domain socket for IPC communication between sandboxed application and network extension(I am porting existing software, so this is not a blind requirement). According this document(https://developer.apple.com/library/archive/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW19) developer should use same app group, which I do.

5. I am using com.apple.security.temporary-exception.files.home-relative-path.read-write in network extension's entitlement to specify name of unix domain socket.

6. When network extension started it fails to create socket - get EPERM error. I can observe created "/var/root/Library/Group Containers/TEAM_ID.com.company.app-group" folder, but there is no socket.

7. Moreover I can observe such error in Console.app: "com.company.MyNetworkExtention: Unsatisfied entitlements: com.apple.security.application-groups"

8. Moreover I can't to write anything to file system in my sandbox from network extension, function NSTemporaryDirectory() returns "<private>"



Any help is greatly appreciated.

Replies

OK, let’s start with some baseline stuff:

  • What platform are you targeting?

  • If it’s the Mac, is your NE provider an app extension or a system extension?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi, my target is mac and I am using network extension autogenerated by xcode ( selected "network extension " project)


Content filter capability of extension is using.

selected "network extension " project

On the Mac there are two Network Extension target templates, one under macOS > Application Extension and one under macOS > System Extension. Which did you choose?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

System Extension.

OK, thanks for clarifying.

Things are kinda tricky given your setup. To start, the App Sandbox puts significant restrictions on UNIX domain sockets. A sandboxed app is not allowed to connect to arbitrary UNIX domain sockets [1].

It is possible to use UNIX domain sockets to communicate between sandboxed apps from the same team. To make this work you have each app join an App Group and then have the listener create the UNIX domain socket within the app group’s container. For example:

let container = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "SKMME9E2Y8.com.example.apple-samplecode.SandboxedUnixDomain.Shared")!
let socketURL = container.appendingPathComponent("listener.sock")
… call `bind` on that path …

IMPORTANT Note that my App Group name does not start with

group
. The
group
prefix is an iOS thing. App Groups work somewhat differently on macOS and do not use this prefix.

The client can do the same thing to connect.

The problem with your setup is that your two programs are running as different users. The sysex runs as root and the container app runs as the logged in user. This will result in two different

container
paths.

Or at least I think it will. I don’t have time to test this myself right now, so I encourage you to confirm that independently.

If I were in your situation I’d probably just switch to using XPC. Build an abstraction layer on top of your existing UNIX domain sockets code [2] and then write a new implementation that runs over XPC.

If that’s not feasible, another option is to use XPC to do the initial setup. That is, change the client to not call

socket
and
connect
directly but rather call an abstraction that returns a connected UNIX domain sockets. Then, in the XPC case, use an XPC call to request that socket from the server itself.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

[1] The various file system temporary exceptions, like

com.apple.security.temporary-exception.files.home-relative-path.read-write
, won’t help with this because those only apply to files, and UNIX domain sockets are not files.

[2] My experience with code like this is that it often already has such an abstraction layer.

  • Hello eskimo. What do you mean by "use an XPC call to request that socket from the server itself"? How exactly to pass a socket through XPC? And how can you manually create a socket?

Add a Comment