IPC connection failed to reconnect after system network extension replacement

I have a system network extension that is installed by my app. When I update my app I also update me system extension by returning ReplacementAction.replace at the actionForReplacingExtension delegate. When the new extension starts, I created a new NSXPCListener with the same mach service name, but the app can’t register to it. I updated from MyExtension version 1 to MyExtension version 2. On the Console logs I see:

launchd: [system:] Service "NetworkExtension.com.MyExtension.2" tried to register for endpoint "machServiceName" already registered by owner: NetworkExtension.MyExtension.1

launchd: [system:] failed activation: name = machServiceName, flags = 0x0, requestor = MyApp[38340], error = 1: Operation not permitted

Replies

Something is odd here. What is the bundle id that you are using for your Network System Extension and what is the MachServiceName that you are using too? What does systemextensionsctl tell you is installed and enabled?

% systemextensionsctl list

The bundle id of my app is: com.MyApp. The bundle id of my Network System Extension is: com.MyApp.MyExtension. The MachServiceName is: teamId.com.MyApp.MyExtension.

systemextensionsctl tell me that MyExtension 2 version is activated enabled

My app and extension are sendboxing

I want to add some configuration that I have: The extension is created the listener:

let newListener = NSXPCListener(machServiceName: machServiceName)
newListener.delegate = self
newListener.resume()

and the app is registered:

    let newConnection = NSXPCConnection(machServiceName: machServiceName, options: [])

    // The exported object is the delegate.
    newConnection.exportedInterface = NSXPCInterface(with: AppCommunication.self)
    newConnection.exportedObject = delegate

    // The remote object is the provider's IPCConnection instance.
    newConnection.remoteObjectInterface = NSXPCInterface(with: ProviderCommunication.self)

    currentConnection = newConnection
    newConnection.resume()

    guard let providerProxy = newConnection.remoteObjectProxyWithErrorHandler({ registerError in
      DDLogError("Failed to register with the provider: \(registerError.localizedDescription)")
      self.currentConnection?.invalidate()
      self.currentConnection = nil
      completionHandler(false)
    }) as? ProviderCommunication else {
      DDLogError("Failed to create a remote object proxy for the provider")
      completionHandler(false)
      return
    }

    providerProxy.register(completionHandler)

With the same machServiceName. Do I need to add com.apple.security.temporary-exception.mach-lookup.global-name and com.apple.security.temporary-exception.mach-register.global-name to the app entitlement file or to the extension entitlement file? If yes, which entitlement need to be in the app and which one in the extension and what should be the value?

Do I need to add com.apple.security.temporary-exception.mach-lookup.global-name and com.apple.security.temporary-exception.mach-register.global-name to the app entitlement file or to the extension entitlement file? 

Are you using the same value here that is in the NEMachServiceName from your Network System Extension's info.plist?

<key>NetworkExtension</key>
<dict>
	<key>NEMachServiceName</key>
	<string>$(TeamIdentifierPrefix)com.MyApp.MyExtension</string>
	...
</dict>

If so, then you should be good, but if this value has changed in your app/extension and it's not declared here in the Network Extension's info.plist then you will have issues.

Also, the container app is a complete app with a UI, correct? Your container app is not a daemon or a command line app correct? The reason I am asking is that there have been issues also with launch a Network System Extension from a container app that does not contain a UI.

The container app is a UI app. I'm using the same value that is in the NEMachServiceName for creating the NSXPCListener and for creating the NSXPCConnection. But do I need to set com.apple.security.temporary-exception.mach-lookup.global-name or com.apple.security.temporary-exception.mach-register.global-name entitlement?

But do I need to set com.apple.security.temporary-exception.mach-lookup.global-name or com.apple.security.temporary-exception.mach-register.global-name entitlement?

If you are using a value that DOES NOT match the value reported in NEMachServiceName then yes. If not, you should be good. For example, I had a Network System Extension that I created that was talking to a daemon on a MachService that was not the MachService reported in the NEMachServiceName (which makes sense right) and so I had to add the mach-lookup.global-name entitlement to the Network System Extension to allow me to communicate on this service.

<key>com.apple.security.temporary-exception.mach-lookup.global-name</key>
<array>
	<string>com.example.apple-samplecode.TransparentProxyTestBedObjC.Daemon</string>
</array>

And the value reported in NEMachServiceName was:

$(TeamIdentifierPrefix)com.example.apple-samplecode.TransparentProxyTestBedObjC.TransparentProxy

All of that to say that it sounds like there are other configuration issues going on here.

@meaton I also have questions regarding this thread: I want that my containing app would be able to talk to its system network extension, via IPC. This is what I've did:

  • I've added temporary-exception.mach-lookup.global-name with the value '$(TeamIdentifierPrefix)com.a.b.c' to the containing app's entitlements
  • I've added temporary-exception.mach-register.global-name with the same value, '$(TeamIdentifierPrefix)com.a.b.c', to the extension's entitlements
  • I've added a code at the containing app, to call extensionMachServiceName(from:) with the same value, '$(TeamIdentifierPrefix)com.a.b.c'
  1. Are the above steps correct? Are they even needed?
  2. The containing app can download (when the user approves) an updated version of both the app and the extension. Then the containing app will replace the extension with the new version, and the containing app will re-launch. Is there any known problem with IPC communication after replacing the app and the extension?

In the case that you have described @roee84, yes, they are needed if the bundle identifier is not the same as what is reported in the NEMachServiceName in the Network Extension. Also, it matters where you are making the XPC connection from, for an example of what I mean by this, see the example for SimpleFirewall.