Sunday, 7 April 2013

2-Months and 4 lines of assembler

I thought I would detail the lack of progress on DTrace/ARM.
Having got DTrace to load on the ARM - I can fire timer tick probes,
I started work on the FBT area. In theory this should have been
straightforward. Having done a load of work on what amounts to about
4 lines of assembler (actually, 5), I thought I would write up my
lack of results. Mainly this is for my benefit - maybe documenting
what I have done will help me.

Theres a useful link here:

I stumbled on this a few days ago, and its very similar to what
I am doing - its comforting its closely aligned, but DTrace doesnt work
that way.

In general, DTrace is doing what a rootkit would do - the same
technologies can be used for nefarious purposes or useful purposes.

So, lets start. In order to stop on an FBT probe, we need to patch
the instruction with a BREAKPOINT instruction. ARM (now, but not in the early
days) has a breakpoint instruction. On the Intel CPUs, a breakpoint
generates an interrupt/trap via the IDT. ARM works differently, and
tracking down a good place to take over the breakpoint handler
proved difficult. (I may have got the code right, but am plagued by
the same problem described below).

So, in order to make this simpler, lets consider the following:


Given the above assembler, lets patch it as follows:

b DTrace_Handler
label: instr3

b label

All instructions are 32b on ARM, and a branch is a single instruction plus
an additional word containing the target label, so, therefore 2 instructions.
If we patch a function, we need to execute the two instructions we
placed. Theres a lot of restrictions about what we do here, e.g.
neither instr1 or instr2 may be the target of a jump in the body of the function.
This is fine for the single function I am targetting (do_PrefetchAbort)
which handles a breakpoint trap. (This patching is part of the mechanism
to allow FBT to work, but it is *not* the mechanism of FBT itself).

Given the above sequence, it should be simple. I can prove the DTrace_Handler
works (eg by adding code to increment a viewable counter) and can
see the function get executed lots of times.

If I then set an FBT breakpoint trap (eg sys_umask is good - only hit
on demand), my kernel hangs. If I avoid modifying do_PrefetchAbort
but do the FBT trap, then I get a kernel error due to an unhandled
breakpoint trap. This latter evidence is useful - I am not crashing
the kernel when the probed function is hit, and I know the FBT code is
doing something.

But combine the two together - the patched code above, and an FBT
breakpoint handler, and the kernel hangs.

Despite only dealing with 4-5 instructions, it does not work. Ergo,
something outside of my expectation area is at work. But I have yet
to find it.

The example in the link referenced above uses a similar mechanism, but
it is not foolproof or SMP/interrupt safe - it can lose some hits;
but the mechanism is similar to what I am doing in DTrace - and just getting
the basics to work is surprisingly difficult (I really need a kernel
debugger to see what is going on - but I havent set one up).

Post created by CRiSP v11.0.16a-b6552

No comments:

Post a Comment