Calling nettop from swift: "Unable to allocate a kernel control socket"

Viewed 119

I am writing a macOS GUI wrapper for the command-line nettop utility.

When I call nettop -P -L 1 from the Terminal app through zsh, it displays proper output, but when I launch the process from within my Swift app, it displays the following in my app:

nettop[19213:2351456] [NetworkStatistics] Unable to allocate a kernel control socket nettop: NStatManagerCreate failed

Is this some sort of permissions or sandboxing issue, and if so, how do I get my app to request the proper permissions?

Code snippet:

func shell(launchPath: String, arguments: [String] = []) -> (String? , Int32) {
    let task = Process()
    task.launchPath = launchPath
    task.arguments = arguments

    let pipe = Pipe()
    task.standardOutput = pipe
    task.standardError = pipe
    task.launch()
    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    let output = String(data: data, encoding: .utf8)
    task.waitUntilExit()
    return (output, task.terminationStatus)
}

...


struct ContentView: View {
    var body: some View {
            Text(shell(launchPath: "/usr/bin/nettop", arguments: ["-P", "-L", "1"]).0 ?? "No Output")
    }
}
1 Answers

This is, indeed, a sandbox issue: nettop operates by creating a com.apple.network.statistics PF_SYSTEM/SYSPROTO_CONTROL socket (an example of the source can be seen at http://newosxbook.com/code/listings/17-1-lsock.c), which can be sandboxed.

Access to this socket is restricted by two layers:

  • The com.apple.private.network.statistics entitlement is enforced when net.statistics_privcheck sysctl is set to 1. That's not your case, since you're execing nettop, which has the entitlement anyway

  • The sandbox profile prevents the creation of system sockets unless explicitly allowed by a

     (allow network-outbound
             (control-name "com.apple.network.statistics")
             (control-name "com.apple.netsrc"))
    

rule.

It seems that the latter case is what happens in your case, though from your detail it's not clear if the fault is in your own app's sandbox profile or the exec'ed nettop. To determine this, try to create the socket yourself - if you can do that, then it's the exec's problem. If you can't, it's your own profile. It's possible to create your own sandbox profiles, but that's something Apple won't ever allow publicly and will probably get you kicked out of the App Store.

Another test - run your app directly from the command line. (that is, in a terminal, then /Applications/path/to/your.app/Contents/MacOS/yourApp) . This way, it is not launched by xpcproxy, and will suffer from less sandboxing constraints.

Related