DevShark
DevShark

Reputation: 9112

App launched from sandboxed app is not sandboxed

I have an untrusted app on macOS that I want to run, but without allowing it to connect to the internet.

What is the best way to achieve this?

My best idea was to build a simplistic launch app in swift in xcode, and sandbox this launcher. From what I read, apps launched from sandboxed apps should themselves be sandboxed.

So my launcher app looks like this:

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!


    func applicationDidFinishLaunching(_ aNotification: Notification) {
        NSWorkspace.shared.open("/path/inside/bundle/to/untrustedApp.app")
        print ("after")

    }

    func applicationWillTerminate(_ aNotification: Notification) {

    }


}

(Note that I used NSWorkspace.shared.open because NSWorkspace.shared.openApp didn't do anything, not even call the completion handler.)

And I added the sandbox capability in xcode, and made sure all boxes where unchecked. Am I doing anything wrong? Or is my understanding off?

Upvotes: 3

Views: 699

Answers (1)

hmedia1
hmedia1

Reputation: 6180

One way is to use NSTask to directly launch the Mach-O executable inside the untrusted app:

  • NSTask inherits the sandbox of the parent app (See here)
  • NSTask lets you specify the Mach-O executable, which is necessary because untrusted.app has it's own code signature, plist files, and entitlements (or lack thereof)

For example, the following trivial application will get the name of the Mach-O executable from:

/path/to/your/ParentApp.app/relative/path/to/Restricted.app

For example, for firefox:

/path/to/your/ParentApp.app/relative/path/to/Restricted.app/Contents/MacOS/firefox

Swift:

func applicationDidFinishLaunching(_ aNotification: Notification) {

    let theMainAppBundle = Bundle.main.bundlePath
    let theChildAppBundle = theMainAppBundle + ("/relative/path/to/RestrictedApp.app")
    let childBundleExecutable = Bundle(path: theChildAppBundle)?.executablePath
    Process.launchedProcess(launchPath: childBundleExecutable ?? "", arguments: [""])
    NSApp.terminate(self)

}

Objective C:

(void)applicationDidFinishLaunching:(NSNotification *)aNotification {

    NSString *theMainAppBundle = [[NSBundle mainBundle] bundlePath];
    NSString *theChildAppBundle = [theMainAppBundle stringByAppendingString:@"/relative/path/to/RestrictedApp.app"];
    NSString *childBundleExecutable = [NSBundle bundleWithPath:theChildAppBundle].executablePath;
    [NSTask launchedTaskWithLaunchPath:childBundleExecutable arguments:[NSArray arrayWithObjects:@"", nil]];
    [NSApp terminate:self];

}

Upvotes: 1

Related Questions