Unable to launch Network Extension On Mac

Hi There,

I have read every previous post in the forum and I still cannot figure out why my network extension cannot be launch with error:

Error Domain=OSSystemExtensionErrorDomain Code=4 "Extension not found in App bundle: perhaps App is not validly structured" UserInfo={NSLocalizedDescription=Extension not found in App bundle: perhaps App is not validly structured}

Things I have tried:

  • I verified the network extension is indeed bundled into the final packet by unzip the the project and look into the package contents:

  • I did tried multiple versions of different entitlements and Info.plist for both the app and extension and none of them worked.
  • I did disable SIP on my Mac.

Here is my entitlements for the extension:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>keychain-access-groups</key>
  <array>
    <string>${TEAM_ID}.group.com.test.vpn</string>
  </array>
  <key>com.apple.security.application-groups</key>
  <array>
    <string>${TEAM_ID}.group.com.test.vpn</string>
  </array>
  <key>com.apple.developer.networking.networkextension</key>
  <array>
    <string>packet-tunnel-provider-systemextension</string>
  </array>
  <key>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.files.user-selected.read-write</key>
	<true/>
	<key>com.apple.security.network.client</key>
  <true/>
  <key>com.apple.security.network.server</key>
  <true/>
  <key>com.apple.application-identifier</key>
 <string>${TEAM_ID}.com.test.vpn.NetworkExtension</string>
</dict>
</plist>

Here is the info.plist for the extension:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>CFBundleDevelopmentRegion</key>
  <string>en</string>
  <key>CFBundleExecutable</key>
  <string>$(EXECUTABLE_NAME)</string>
  <key>CFBundleIdentifier</key>
  <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
  <key>CFBundleInfoDictionaryVersion</key>
  <string>6.0</string>
  <key>CFBundleName</key>
  <string>${CF_BUNDLE_NAME}</string>
  <key>CFBundlePackageType</key>
  <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
  <key>CFBundleShortVersionString</key>
  <string>${VERSIONINFO_SHORT}</string>
  <key>CFBundleVersion</key>
  <string>${VERSIONINFO_LONG}</string>
  <key>CFBundleDisplayName</key>
  <string>${PRODUCT_NAME}</string>
  <key>CFBundleURLTypes</key>
  <array>
    <dict>
      <key>CFBundleURLSchemes</key>
      <array>
        <string>${AUTHENTICATION_SCHEME}</string>
      </array>
    </dict>
  </array>
  <key>APPClientId</key>
  <string>${APP_CLIENT_ID}</string>
  <key>NetworkExtension</key>
  <dict>
	<key>NEMachServiceName</key>
	<string>${TEAM_ID}.com.test.vpn.NetworkExtension</string>
	<key>NEProviderClasses</key>
	<dict>
		<key>com.apple.networkextension.packet-tunnel</key>
		<string>VPNPacketTunnelProvider</string>
	</dict>
  <key>NSSystemExtensionUsageDescription</key>
	<string></string>
</dict>
</dict>
</plist>

Here is the entitlements for the app:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>com.apple.security.files.user-selected.read-write</key>
        <true/>
        <key>com.apple.security.network.client</key>
        <true/>
        <key>com.apple.security.network.server</key>
        <true/>
        <key>com.apple.developer.networking.networkextension</key>
        <array>
          <string>packet-tunnel-provider-systemextension</string>
        </array>
        <key>com.apple.security.app-sandbox</key>
      	<true/>
        <key>com.apple.security.application-groups</key>
	      <array>
      		<string>${TEAM_ID}.group.com.test.vpn</string>
       	</array>
        <key>com.apple.developer.system-extension.install</key>
        <true/>
        <key>com.apple.application-identifier</key>
        <string>${TEAM_ID}.com.test.vpn</string>
</dict>
</plist>

Any thing did I misconfigure or any steps did I miss?

Any thing did I misconfigure or any steps did I miss?

Thank you very much for adding the image of your bundle. This does make it clear what is happening. See the .appex on your Network Extension. You have a Network App Extension in your project and it looks like you are trying to deploy a Network System Extension with Developer ID. The reason I can tell that is these values:

<key>com.apple.developer.networking.networkextension</key>
<array>
    <string>packet-tunnel-provider-systemextension</string>
</array>
<key>com.apple.developer.system-extension.install</key>
<true/>

There are two flavors of Network Extensions, Network System Extension and Network App Extensions. Network System Extension are require when deploying via Developer ID.

Regarding:

I did disable SIP on my Mac.

Turn SIP back on. You are only making life harder on yourself.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

Thanks Meaton for your response!

There are two flavors of Network Extensions, Network System Extension and Network App Extensions. Network System Extension are require when deploying via Developer ID.

Yeah, you are right, I am trying to create a system extension instead of an app extension. But I am not sure why it bundles an app extension into my final package. Is it related to my provisioning file? Or any there anything I missed? I am trying to reuse the packet tunnel subclass with iOS. Is this the root cause for it?

Turn SIP back on. You are only making life harder on yourself.

Thanks so much! I actually had a hard time to convince my security team regrading disabling SIP.

But I am not sure why it bundles an app extension into my final package. Is it related to my provisioning file?

No, your provisioning profile looks like it's setup for signing a Developer ID based Network System Extension correctly.

I suspect what happened here is that when you created the extension in Xcode you did File -> New -> Target -> Network Extension [First Panel under App Extension], instead of File -> New -> Target -> Network Extension [Last Panel under System Extension]. For iOS an app extension is reasonable, but on macOS this does make a difference.

Regarding:

I am trying to reuse the packet tunnel subclass with iOS. Is this the root cause for it?

If you mean that you are sharing the same iOS App Extension to macOS, then yes. On macOS NEPacketTunnelProviders that are distributed via Developer ID need to be System Extensions and not App Extensions.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

Thanks for the reply, I finally reached the point that I can generate a systemextension for my project:

However, I still have a hard time launching the my VPN (Packet Tunnel Provider):

If I disable SIP on my Mac, I am seeing this error: Error Domain=NEVPNErrorDomain Code=5 "permission denied" UserInfo={NSLocalizedDescription=permission denied}

If I enable SIP on my Mac, I am seeing a different error: deny(1) mach-lookup com.apple.sysextd

So I added following code into my container app's entitlements:

<key>com.apple.security.temporary-exception.mach-lookup.global-name</key>
<array>
  <string>com.apple.sysextd</string>
</array>

And now I am getting a different error again:  Error Domain=OSSystemExtensionErrorDomain Code=8 "Invalid code signature or missing entitlements" UserInfo={NSLocalizedDescription=Invalid code signature or missing entitlements}

Any ideas about what I am missing again here?

If I disable SIP on my Mac

Do not disable SIP!!!

You should not need to add an exception for com.apple.security.temporary-exception.mach-lookup.global-name.

With a network system extension, you need to do the following:

  1. Install the System Extension. Look at OSSystemExtensionRequest.activationRequest and it's delegate methods for doing this.

  2. Configure the Network Configuration for the Packet Tunnel. This process should be familiar in that you need to load a NETunnelProviderManager and configure the NETunnelProviderProtocol against it. Then save the configured NETunnelProviderManager with saveToPreferences.

Note, make sure that the bundle identifier for your Network System Extension is added to providerBundleIdentifier in NETunnelProviderProtocol.

  1. Load the NETunnelProviderManager again and then call startVPNTunnel on NEVPNConnection.

  2. You should see startTunnel being hit then in your NEPacketTunnelProvider to configure and start the actual tunnel.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

I did follow the steps, here are some critical snippet:

- (void)request:(nonnull OSSystemExtensionRequest *)request
    didFinishWithResult:(OSSystemExtensionRequestResult)result {
   if (result != OSSystemExtensionRequestCompleted) return;
   [NETunnelProviderManager loadAllFromPreferencesWithCompletionHandler:^(
                                   NSArray<NETunnelProviderManager *> *managers, NSError *error) {
        if (error) {
          NSLog("load error: %@", error);
          return;
        }

        NETunnelProviderManager *manager = managers.firstObject;
       if (manager) {
         [self saveManager:manager options:options];
         return;
       }

       NETunnelProviderProtocol *protocol = [[NETunnelProviderProtocol alloc] init];
       protocol.serverAddress = @"unused";
       protocol.disconnectOnSleep = NO;
       protocol.providerBundleIdentifier = @"com.test.vpn.NetworkExtension";

       NETunnelProviderManager *newManager = [[NETunnelProviderManager alloc] init];
       newManager.protocolConfiguration = protocol;
       newManager.localizedDescription = @"Test VPN";
       newManager.enabled = YES;
       [self saveManager:newManager options:options];
      }];
    }
}

- (void)saveManager:(NETunnelProviderManager *)manager
            options:(NSDictionary<NSString *, id> *)options {
  [manager saveToPreferencesWithCompletionHandler:^(NSError *_Nullable saveError) {
    if (saveError) {
      NSLog(@"Failed to save with error: %@", saveError);
      return;
    }

    [manager loadFromPreferencesWithCompletionHandler:^(NSError *_Nullable loadError) {
      if (loadError) {
        NSLog(@"Failed to load with error: %@", loadError);
        return;
      }

      NSError *error;
      BOOL success = [manager.connection startVPNTunnelWithOptions:options andReturnError:&error];

      if (!success || error) {
        NSLog(@"Failed to start with error: %@", error);
        return;
      }
      NSLog(@"Did start VPN")
    }];
  }];
}

When I run it on my Mac with SIP disabled, I am seeing error: Failed to save with error: Error Domain=NEVPNErrorDomain Code=5 "permission denied" UserInfo={NSLocalizedDescription=permission denied}

This seems to indicate the NETunnelProviderManager.saveToPreferencesWithCompletionHandler is throwing an error. Any idea of what's going wrong here?

Okay, I do not see anything specifically wrong with your setup. I did want to confirm that you did install your Network System Extension:

OSSystemExtensionRequest * request = [OSSystemExtensionRequest activationRequestForExtension:@"com.test.vpn.NetworkExtension" queue:dispatch_get_main_queue()];
request.delegate = self;
[OSSystemExtensionManager.sharedManager submitRequest:request];

And that your actual container app's bundle identifier looks like:

com.test.vpn

Because you have your NEPacketTunnelProvider referenced as:

protocol.providerBundleIdentifier = @"com.test.vpn.NetworkExtension";

Also, when you run this, are you running this from the /Applications directory? If not, try running your built app in the /Applications directory no matter if you are building from Xcode or have a built copy of your app that is Developer ID signed and Notarized.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

Nice, I am finally able to launch the My PacketTunnelProvider code, however I am seeing this error in my console, not sure what it means:

Sandbox: com.test.vpn.d(65504) deny(1) mach-lookup com.apple.AppSSO.service-xpc
Violation:    deny(1) mach-lookup com.apple.AppSSO.service-xpc
Process:     com.test.vpn.d [65504]
Path:      /Library/SystemExtensions/2EA7CA6C-4185-4D33-A43B-8ACAE5C4BFFA/com.test.vpn.NetworkExtension.systemextension/Contents/MacOS/com.test.vpn.NetworkExtension
Load Address:  0x101e01000
Identifier:   com.test.vpn.NetworkExtension
Version:     1 (1.0)
Code Type:    x86_64 (Native)
Parent Process: launchd [1]
Responsible:   /Library/SystemExtensions/2EA7CA6C-4185-4D33-A43B-8ACAE5C4BFFA/com.test.vpn.NetworkExtension.systemextension/Contents/MacOS/com.test.vpn.NetworkExtension
User ID:     0

Date/Time:    2022-03-25 16:48:03.273 PDT
OS Version:   macOS 12.3 (21E230)
Release Type:  User
Report Version: 8

MetaData: {"target":"com.apple.AppSSO.service-xpc","responsible-process-signing-id":"com.test.vpn.NetworkExtension","policy-description":"Sandbox","mach_namespace":1,"responsible-process-team-id":"QEXH8ZM8AV","normalized_target":["com.apple.AppSSO.service-xpc"],"profile-flags":0,"errno":1,"platform-policy":false,"primary-filter":"global-name","global-name":"com.apple.AppSSO.service-xpc","operation":"mach-lookup","platform-binary":false,"process-path":"\/Library\/SystemExtensions\/2EA7CA6C-4185-4D33-A43B-8ACAE5C4BFFA\/com.test.vpn.NetworkExtension.systemextension\/Contents\/MacOS\/com.test.vpn.NetworkExtension","platform_binary":"no","primary-filter-value":"com.apple.AppSSO.service-xpc","container":"\/private\/var\/root\/Library\/Containers\/com.test.vpn.NetworkExtension\/Data","hardware":"Mac","checker":"launchd","profile-in-collection":false,"sandbox_checker":"launchd","build":"macOS 12.3 (21E230)","action":"deny","summary":"deny(1) mach-lookup com.apple.AppSSO.service-xpc","checker-pid":1,"pid":65504,"process":"com.test.vpn.d","flags":5,"signing-id":"com.test.vpn.NetworkExtension","binary-in-trust-cache":false,"team-id":"QEXH8ZM8AV","responsible-process-path":"\/Library\/SystemExtensions\/2EA7CA6C-4185-4D33-A43B-8ACAE5C4BFFA\/com.test.vpn.NetworkExtension.systemextension\/Contents\/MacOS\/com.test.vpn.NetworkExtension","apple-internal":false,"uid":0,"release-type":"User"}
Unable to launch Network Extension On Mac
 
 
Q