Using `SecCodeCopyGuestWithAttributes` with auditToken results in `100001 - UNIX[Operation not permitted]`

Hi everyone :)

I'm exploring XPC these days; more specifically, I'm trying to establish a connection between a macOS application and an XPC service. I succeeded in establishing the connection, but now I'm trying to verify the incoming connection by using SecCodeCopyGuestWithAttributes, passing it an audit token.

But I got the following error:

2024-01-18 10:43:06.805435+0100 DemoService[1627:7118397] [logging-persist] cannot open file at line 46922 of [554764a6e7]
2024-01-18 10:43:06.805452+0100 DemoService[1627:7118397] [logging-persist] os_unix.c:46922: (0) open(/private/var/db/DetachedSignatures) - Undefined error: 0
Cannot get SecCode: 100001 - UNIX[Operation not permitted]
Audit token: Optional(32 bytes)

The last two lines come from my code:

class XPCClientValidator {
    var secCodeOptional: SecCode? = nil;
    
    func identifyGuest(for connection: NSXPCConnection) -> Bool {
        let auditToken = AuditToken.extractToken(from: connection)
        let hostSecCode: SecCode? = nil; // This is a way to indicate that the code signing root of trust hould be used as host.
        let attributes = [ kSecGuestAttributeAudit: auditToken ] as CFDictionary
        let secFlags = SecCSFlags(rawValue: 0)
        
        // Asks a code host to identify the guest given the audit token
        let status: OSStatus = SecCodeCopyGuestWithAttributes(hostSecCode, attributes, secFlags, &self.secCodeOptional)
        if (status != errSecSuccess) {
            let msg = SecCopyErrorMessageString(status, nil)!
            print("Cannot get SecCode: \(status) - \(msg)")
            print("Audit token: \(String(describing: auditToken))")
            return false
        }
        
        guard let _ = secCodeOptional else {
            NSLog("Couldn't unwrap the secCode")
            return false
        }
        
        return true
    }
}

I saw a few posts on the forum, but nothing helped me to solve this issue.

The complete source code is here: https://github.com/tony-go/XPCDemo/tree/secure-xpc

Note: If you want to reproduce it, you have to:

  • start the app
  • type a random input
  • click on "uppercase it"

Accepted Reply

now I'm trying to verify the incoming connection by using SecCodeCopyGuestWithAttributes

To what end?

If you’re building an XPC service that’s embedded within your app, its named XPC endpoint is only exported in your app’s namespace. Thus, only your app can connect to it. Doing an extra level of checking is pointless.

If your named XPC endpoint is available elsewhere, say you’re building a launchd agent, or you just want to add some pointless extra code (-; your best option is to do this declaratively, by configuring your XPC listener with a code signing requirement. See Validating Signature Of XPC Process.

Is it acceptable to remove the sandbox for an XPC service?

In general, yes. If you plan to deploy via the Mac App Store, then no.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Replies

Note: I know that calling SecCodeCopyGuestWithAttributes is not enough, my goal is to use SecCodeCopyStaticCode and then perform a few checks.

Disabling sandbox for the Service worked.

Then I try to re-enable it and authorize this:

But it did not worked...

Is it acceptable to remove the sandbox for an XPC service?

now I'm trying to verify the incoming connection by using SecCodeCopyGuestWithAttributes

To what end?

If you’re building an XPC service that’s embedded within your app, its named XPC endpoint is only exported in your app’s namespace. Thus, only your app can connect to it. Doing an extra level of checking is pointless.

If your named XPC endpoint is available elsewhere, say you’re building a launchd agent, or you just want to add some pointless extra code (-; your best option is to do this declaratively, by configuring your XPC listener with a code signing requirement. See Validating Signature Of XPC Process.

Is it acceptable to remove the sandbox for an XPC service?

In general, yes. If you plan to deploy via the Mac App Store, then no.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks a lot :) @eskimo

Thus, only your app can connect to it.

So when my XPCS service is up, no potential men in the middle could try to connect? Where I can find official Apple documentation about this?

If your named XPC endpoint is available elsewhere, say you’re building a launchd agent [...]

Oh, that is the difference then.

So when my XPC service is up, no potential men in the middle could try to connect?

Yes, assuming that service is embedded within your app and you’ve not done anything silly with the ServiceType property.

Where I can find official Apple documentation about this?

The xpcservice.plist man page says:

Each application will have a unique instance of this service.

which isn’t quite what you’re looking, for but it’s close.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"