Re: [RFC PATCH 4/6] uprobes/x86: Emulate rip-relative call's

From: Jim Keniston
Date: Wed Apr 09 2014 - 17:25:52 EST


On Wed, 2014-04-09 at 17:43 +0200, Oleg Nesterov wrote:
> On 04/08, Jim Keniston wrote:
> >
> > On Sun, 2014-04-06 at 22:16 +0200, Oleg Nesterov wrote:
> > > 0xe8. Anything else?

Oleg, thanks for responding to (if not necessarily agreeing with) all my
suggestions. I think your code is solid, but I think we were wrong
about one thing. See below.

> >
> > No, I think e8 is the only call instruction uprobes will see.
>
> Good.
>
> > The following couple of paragraphs should be included in the code,
> > perhaps merged with some of the related comments already there. Without
> > it, the code is pretty hard to follow.
>
> OK, I'll try to improve the comments somehow...
>
> > > Emulating of rip-relative call is trivial, we only need to additionally
> > > push the ret-address. If this fails, we execute this instruction out of
> > > line and this should trigger the trap, the probed application should die
> > > or the same insn will be restarted if a signal handler expands the stack.
> > > We do not even need ->post_xol() for this case.
> > >
> > > But there is a corner (and almost theoretical) case: another thread can
> > > expand the stack right before we execute this insn out of line. In this
> > > case it hit the same problem we are trying to solve. So we simply turn
> > > the probed insn into "call 1f; 1:" and add ->post_xol() which restores
> > > ->sp and restarts.
> >
> > Can you explain under what circumstances emulation of the call
> > instruction would fail? Will the copy_to_user() call that writes the
> > return address to the stack grow the stack if necessary?
>
> If necessary and if possible.
>
> > Will
> > single-stepping the mangled call instruction expand the stack?
>
> In the likely case it won't. If copy_to_user() failes, then "call" should
> fail too (again, ignoring the potential race with another thread which can
> populate the memory ->sp - 8 points to).


I've experimented with putting a uprobe on a call instruction (in a
tight loop, with no ret) and a kprobe on expand_stack(), and my results
seem to indicate that a single-stepped call instruction will
successfully grow the stack vma where a call to copy_to_user() won't.

So your trick of single-stepping the mangled call after the failed
emulation, and then retrying the emulation should come into play in more
than just theoretical situations. We'd need it any time the probed call
needs to grow the stack vma.

I can send you the test kprobe/uprobe modules I used, if you like.

Bottom line: no further code changes, but this would affect your
comments.

Jim

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/