Granary / granary2

Dynamic binary translation framework for instrumenting x86-64 user space Linux programs
MIT License
39 stars 5 forks source link

Transparent returns where execution should return to native code #59

Open pgoodman opened 10 years ago

pgoodman commented 10 years ago

This issues occurs when transparent returns are enabled for kernel mode instrumentation. The kernel entrypoints are the system call functions themselves (as opposed to the real system call entrypoint). These functions, when instrumented, should go native when they return. It's not clear what the right way to accomplish this is. One approach is to use an inverted index of code cache block heads to meta-data. This will be useful and needed anyway, so is potentially the ideal case. Another approach is to wrap the entrypoints with an extra call, as is done with function wrappers. This seems less ideal.

pgoodman commented 10 years ago

The issue here is really: the system call functions are called indirectly via some entrypoint code targeted by the syscall-specific MSR. This code sets up the gs segment registers, switches stacks, saves/restores registers, and sometimes does sanity checks. Summary: it is very low-level code, some of which--if instrumented--might not work with Granary (particularly the use of swapgs).

If transparent returns are enabled, then we'll start by instrumenting the syscall entrypoints with RetAddrInCodeCache::returns_to_cache == true, but once we call another function, this will become false, and so when that function eventually returns, it will be false, and when the system function itself returns, that return will be instrumented, and translation will continue into the code that eventually leads to swapgs and sysret et al. This will be bad!

pgoodman commented 10 years ago

I think a reasonable solution to this could be:

Apply the same function wrapping techniques to system calls (thus introducing an extra call). Have a special InstrumentExitPoint method for tools, and make it so that if execution reaches one of these special wrappers (perhaps placed in a new section of Granary's binary), then a stub InstrumentExitPoint with a jump going to a NativeBasicBlock will be fine.

It would also be nice to canonicalize this further: Have a similar approach for interrupts, such that interrupts have entry/exit points, and syscalls have entry/exit points.

Then the last real challenge is for user space threads, i.e. after a clone, instrumenting the first block of the new thread as an entrypoint, then the issue turns into better (than the present) system call wrapping, which is on the TODO list anyway.