lldb fails to launch process: "Not allowed to attach to process"

Xcode 12.4 on Big Sur, a very basic attempt to launch and debug a process.

Code Block
Little-Net:host-osx minfrin$ lldb ./tmp_firefox/Library/Google/Chrome/NativeMessagingHosts/chrome-token-signing.app/Contents/MacOS/chrome-token-signing
(lldb) target create "./tmp_firefox/Library/Google/Chrome/NativeMessagingHosts/chrome-token-signing.app/Contents/MacOS/chrome-token-signing"
Current executable set to '/Users/minfrin/src/redwax/open-eid/chrome-token-signing-trunk/host-osx/tmp_firefox/Library/Google/Chrome/NativeMessagingHosts/chrome-token-signing.app/Contents/MacOS/chrome-token-signing' (x86_64).
(lldb) process launch -i cert.native 
error: process exited with status -1 (attach failed (Not allowed to attach to process.  Look in the console messages (Console.app), near the debugserver entries when the attached failed.  The subsystem that denied the attach permission will likely have logged an informative message about why it was denied.))


Why would lldb, running as my local user, be unable to launch a process also running as my local user?

Is there any way to convince lldb to log error messages instead of referring me to the console, which contains a continuous stream of noise?

Replies

Is there any way to convince lldb to log error messages instead of
referring me to the console … ?

No, because the API that’s failing on LLDB does not return comprehensive error information (IIRC LLDB is just getting back EPERM).

which contains a continuous stream of noise

These log entries are only “noise” if they don’t apply to your specific situation (-: The trick here is to filter. In this case I recommend the following:
  1. Reproduce the problem.

  2. Run log collect.

  3. Open the resulting .logarchive with Console.

  4. Search for debugserver entries.

  5. Search backwards from there to find a more detailed explanation.

In my test, where I tried attaching to the Finder, I saw this:

type: default
time: 2021-03-16 12:23:23.970146 +0000
process: kernel
category: <Missing Description>
message: macOSTaskPolicy: (com.apple.debugserver) may not get the taskport of (Finder) (pid: 448): (Finder) is hardened, (Finder) doesn't have get-task-allow, (com.apple.debugserver) is a declared debugger

which is pretty clear: I can’t attach to the Finder because the executable has the hardened runtime enabled but doesn’t have the get-task-allow entitlement set [1].

Why would lldb, running as my local user, be unable to launch a
process also running as my local user?

There are lots of reasons why LLDB might not be able to attach, which is why it points you to the system log rather than trying to diagnose the issue itself. These mostly boil down to the way that the program is signed. For example, consider this:

Code Block
% codesign -d -vvv --entitlements :- /Applications/QProcessDock.app
CodeDirectory v=20500 size=1365 flags=0x10000(runtime) …
<plist version="1.0">
<dict/>
</plist>


This app has the hardened runtime set (hence the runtime flag). This enables a bunch of extra security features by default, and one of those is to prevent the debugger from attaching. You can re-enable this by setting the get-task-allow entitlement (com.apple.security.get-task-allow) but in this specific case that’s not set.

As to what’s preventing chrome-token-signing from running, it’s hard to say without more info. Try the diagnostics I’ve outlined above and let us know what you see.

Share and Enjoy

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

[1] Actually, the Finder is a platform binary so it doesn’t have to opt in to the hardened runtime because that’s enabled by default for all platform binaries.
Thanks @eskimo for your detailed help on these topics, here and elsewhere. I think it is worth mentioning that (at least on Big Sur) the reason why the debuggee wants com.apple.security.get-task-allow, is that in the lldb workflow, there is no run vs. attach distinction (in gdb parlance) — lldb always wants to attach to an already-running process (through its debugserver helper).

I determined experimentally today¹ that gdb only needs the com.apple.security.cs.debugger in order to debug a process that it starts up itself (presumably corresponding to the is a declared debugger verbiage in the kernel logs). However, lldb never does that; instead, it runs the process un-debugged and then attempts to have something called debugserver attach to it — As it turns out, debugserver also has com.apple.security.cs.debugger entitlement (as it should).

As that would enable something called a lateral-move attack, attaching to an already-running process is an operation that is obviously more appealing to malware than creating a subprocess (which is unlikely to gain privilege) and debugging it; therefore it makes sense that that action requires additional checks, i.e. an com.apple.security.get-task-allow signed entitlement on the target (the debuggee, not the debugger) — Under the justification that one should only want to (attach to and) debug programs that one wrote oneself.

Long story short — This works:

Code Block shell
cat > debuggee-entitlement.xml <<ENTITLEMENT
<?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.get-task-allow</key>
<true/>
</dict>
</plist>
ENTITLEMENT
codesign --entitlements debuggee-entitlement.xml -fs gdb-cert ./ls
lldb ./ls


(where gdb-cert should be replaced with the name of whichever certificate you usually sign code with)

¹ I did run into more bugs though, e.g. 24069 which I unfortunately cannot seem to link to here — Different story.

i was able to get the attach to succeed by removing the hardened runtime capability from the Signing and Capabilities tab in the target preferences. how obscure is that? and i do not know what will be the negative consequences of doing this.

i do not know what will be the negative consequences of doing this.

The hardened runtime is required for products that you distribute independently, using Developer ID signing, and recommended for apps that you distribute via the Mac App Store.

The hardened runtime opts your process in to a bunch of security features. For the details, see Hardened Runtime.

I recommend that you leave the hardened runtime enabled during development. Otherwise you might not see an incompatibility until you go to distribute your product, and that’ll make things harder to debug.

If you’re building an app from Xcode then it should apply the get-task-allow entitlement to development builds. If that’s not happening, it’s most likely because you don’t have Code Signing Inject Base Entitlements (CODE_SIGN_INJECT_BASE_ENTITLEMENTS) enabled. There are reasons to turn this off — for an example of where that’s necessary, see Embedding a Command-Line Tool in a Sandboxed App — but in most case you want it enabled.

Share and Enjoy

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

where do i add the get-task-allow and CODE_SIGN_INJECT_BASE_ENTITLEMENTS? I added them both to my plist, but with hardened runtime added, xcode won't attach, and with it not added, xcode will. so, if your answer is, yes, to your plist, then my question becomes: what else do i also need to do in addition to adding those two?

Furthermore, adding CODE_SIGN... and removing hardened runtime cause Xcode to not be able to launch my app. removing both allows normal launch and debug to succed. Is this known? Can you explain?

For those following along at home, I’m going to be helping rickety train in another context.

Share and Enjoy

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