Mac OS X Expert Challenge 2005.1

Winner: Alexey Proskuryakov

Analysis

Panpipes creates a Mach task, then calls exit() from it. In a more detailed manner:

  1. It runs from a static init routine, thus attempts to break on main() fail. I used DYLD_PRINT_INITIALIZERS environment variable to ask dyld to display all initializers.
  2. The init routine deciphers in RAM (syscalls for mach_reply_port, thread_self, mach_msg, mach_msg_overwrite, exit, ptrace). I simply stepped through the routine, then used x/i to display the code.
  3. Then, it calls task_set_exception_ports to disable debugging. It does this manually, via a mach_msg trap, making it pretty hard to guess what's going on. Again, some stepping, plus grepping Mach sources to find the function for this msgh_id. I removed the call from the binary to simplify further investigation.
  4. Then, it creates a new thread (with main() as the routine). Obviously, this also makes debugging somewhat harder.
  5. main() creates a new Mach task, and three threads in it (obviously all Mach calls are still performed manually).
  6. For one of the threads, it changes the state (srr0, sp and lr registers) and resumes it.
  7. The functions in srr0 and lr pretend to do something with IOKit, but this seems to be red herring — a plain exit(0) gives the same kernel panic for me.

Proposed Fix

As I understand the issue, it's unix_syscall expecting that the current task is a BSD one (I looked at the exception state in panic log for the addresses, then used gdb on /mach_kernel to find out symbolic names.

0x002a6b68 <unix_syscall+184>: bl 0x40e70 <get_bsdtask_info> 0x002a6b6c <unix_syscall+188>: b 0x2a6b74 <unix_syscall+196> 0x002a6b70 <unix_syscall+192>: bl 0x2a8228 <current_proc> 0x002a6b74 <unix_syscall+196>: lwz r30,256(r31) 0x002a6b78 <unix_syscall+200>: mr r28,r3 0x002a6b7c <unix_syscall+204>: lwz r0,8(r3) <panic here>

Thus, there should be a check that get_bsdtask_info returns a non-zero value.

On 10.3, the panic happens in a different place (in proc_is_classic). Again, the function does not check its input parameter for being zero, so the basic mechanism appears to be the same.

Time Spent

It took me about 15 hours to write this letter.

Bio

I graduated from the Moscow State University, where I studied Mathematics, in 1999. I have been a Mac user, admin, and developer since 1993 — mostly C++/Carbon, with small trips into Cocoa and UNIX lands.

Alexey Proskuryakov

Amit: The astute reader will notice some minor discrepancies between this analysis and my description of panpipes. However, I point this out for technical accuracy: given that Alexey essentially started with a black box, the amount of detail he extracted is amazing.