

Hacking the OS X Kernel for Fun and Profiles - f2f
http://research.swtch.com/macpprof

======
spudlyo
It's articles like this that keep me reading HN. Kernel bugs, POSIX thread
details, code disassembly, binary patching, _and_ I get to learn about a new
signal. What's not to love?

~~~
SecretofMana
The paper on KSplice attached at the end is also really neat if you're into
this stuff. It describes the design and implementation of a tool for applying
binary patches based on normal source code diffs.

------
lelf
At least thanks apple for not stripping everything

    
    
      Betty:~ lelf$ dsymutil -s /mach_kernel |head
      ----------------------------------------------------------------------
      Symbol table for: '/mach_kernel' (x86_64)
      ----------------------------------------------------------------------
      Index    n_strx   n_type             n_sect n_desc n_value
      ======== -------- ------------------ ------ ------ ----------------
      [     0] 00000004 0f (     SECT EXT) 08     0000   ffffff800084e79c '.constructors_used'
      [     1] 00000017 0f (     SECT EXT) 08     0000   ffffff800084e7a4 '.destructors_used'
      [     2] 00000029 0f (     SECT EXT) 01     0000   ffffff80005241b0 '_AddFileExtent'
      [     3] 00000038 0f (     SECT EXT) 01     0000   ffffff800051ef40 '_AllocateNode'
      [     4] 00000046 0f (     SECT EXT) 01     0000   ffffff800021d510 '_Assert'

------
klodolph
> In order for the open file not to be inherited by the new program, we must
> introduce a new variant of open(2) that can open a file descriptor
> atomically marked "close on exec."

This is incorrect, because you can prevent fds from getting inherited even
without "close on exec". Simply list the files in /dev/fd and you'll see all
the file descriptors your program has open, and then you can close all of the
ones that the exec'd program won't need. The same thing is done on Linux with
/proc/self/fd. The whole facility gets wrapped in a library function (not a
standard library function, sadly) since there is a minor trick involved in
getting this right.

The problem with close on exec is that libraries would have to be modified to
ensure they mark descriptors as close-on-exec. The current system is
admittedly arcane and non-portable, but it does work.

~~~
mikeash
Last time I checked on this, there was no safe way (i.e. using only async-
signal-safe calls) to list the contents of /dev/fd post-fork. Did I miss
something?

~~~
klodolph
You can call functions that aren't async-signal-safe after a fork(). The
standard library has prefork handlers that fire ensuring that you can e.g.
opendir() safely after fork(), even if another thread was halfway through
malloc() at the time of the fork.

Forking + threads is very messy, but it's not quite _that_ pathological. I'd
like to see an interface similar to posix_spawn() become the norm for spawning
processes, with a fallback to fork()+exec() for more difficult use cases, but
I don't think posix_spawn() is good enough.

~~~
mikeash
Well, the man page says otherwise, and I'd hate to rely on undocumented safety
buried in the standard library.

Edit: upon re-reading the man page, this bit caught my eye:

"If you need to use these frameworks in the child process, you must exec. In
this situation it is reasonable to exec yourself."

So that would be one (highly painful) way to handle this safely. Fork, then
self-exec, passing in arguments that tell the newly execed process what you
really want to run. The new process can then do the /dev/fd listing in peace,
then call exec again. Eww.

~~~
klodolph
Seems like you're right. Whoops, time to go fix some of my code, which is why
I really want a non-broken posix_spawn().

Another silly way to do things is to have the parent process send a list of
fds to close over a pipe, which at least doesn't require a second call to
exec().

I think the problem with close-on-exec is always going to be simple though:
you have to make sure _every library_ you use sets the flag.

~~~
bdash
OS X provides the POSIX_SPAWN_CLOEXEC_DEFAULT flag to posix_spawn, which
results in it automatically closing all file descriptors that aren't described
by the file actions passed to posix_spawn.

------
mzs
Cool, that was a bug, and not too difficult to fix and must have felt great
when figured-out. But sometimes on darwin you run into stuff that just is so
crufty in the BSD emulation, that it's better to use the mach stuff. In this
case these class of routines:

    
    
      http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/task_sample.html

~~~
rsc
I don't think that has a way to get stacks. See
[http://research.swtch.com/pprof](http://research.swtch.com/pprof) for why
stacks are important.

~~~
mzs
In that case another task using clock_alarm(), task_suspend(), task_resume(),
and thread_get_state().

------
janus
Can someone explain what this patch actually does? I have an old Macbook Air
with a malfunctioning sensor that cause the CPU to always run in powersaving
mode (capped at 800 mhz), so it's basically unusable under OS X.

I have walked around this issue by installing Linux which allows me to tune
the CPU governor manually, and it uncaps the artificial limit that the
malfunctioning sensor puts.

Would this patch allow me to do something similar in Mountain Lion?

~~~
Moto7451
You could try NullCPUPowerManagement.kext. It's used in the OS X x86 community
to disable the built in Power management. If you don't mind getting your hands
dirty you might be able to get it (or another related kext) to turn off
frequency switching.

[1][http://www.osx86.net/downloads.php?do=file&id=16](http://www.osx86.net/downloads.php?do=file&id=16)

~~~
janus
I don't mind getting my hands dirty at all. I'll see if I can find any more
info about this kext, thanks :)

------
asveikau
So you can't boot OS X by taking stock Darwin/XNU and recompile? If so that is
kind of disappointing. I understand they have private code that they don't
want to open up but it would be nice if you could still boot with a self-
compiled kernel.

~~~
bdash
You can. See [http://shantonu.blogspot.com/2012/07/building-xnu-for-
os-x-1...](http://shantonu.blogspot.com/2012/07/building-xnu-for-
os-x-108-mountain-lion.html)

~~~
asveikau
Glad to hear. It was suspect. "I can't be bothered to figure out how to build
so I guess we'll patch the binary."

I guess Apple doesn't exactly shout from the rooftops how to do this but I see
now that this is the top Google hit for "building xnu". So it's not _too_
hidden.

------
f2f
I'm afraid the title may scare people off the article. i assure you, "hacking"
here is used in the canonical sense: "An incredibly good, and perhaps very
time-consuming, piece of work that produces exactly what is needed."

~~~
endlessvoid94
I think the "hacking X for fun and profit" is a pretty well-known trope.

~~~
tonyarkles
For me, the origin of this was from "Smashing the stack for fun and profit
(1996)"[1], which does actually refer to somewhat malicious purposes.
Apparently it has existed in literature for a long time before that though[2].

[1]
[http://www.phrack.org/issues.html?id=14&issue=49](http://www.phrack.org/issues.html?id=14&issue=49)
[2] [http://english.stackexchange.com/questions/25205/what-is-
the...](http://english.stackexchange.com/questions/25205/what-is-the-origin-
of-phrase-for-fun-and-profit)

~~~
endlessvoid94
Hah, indeed. I had that Aleph One article printed out and stapled, and would
carry it with my books in high school!

------
emacsitor
Can anyone provided an explanation of how the binary patch is applied?

~~~
f2f
If you're familiar with Go you can read the source of the apply function here:

the loadKernel function reads in the kernel and builds a symbol table looking
for the bsd_ast and current_thread symbols here:

[https://code.google.com/p/rsc/source/browse/cmd/pprof_mac_fi...](https://code.google.com/p/rsc/source/browse/cmd/pprof_mac_fix/main.go#231)

then the "apply" func writes the modified binary instructions code:

[https://code.google.com/p/rsc/source/browse/cmd/pprof_mac_fi...](https://code.google.com/p/rsc/source/browse/cmd/pprof_mac_fix/main.go#464)

