This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
Re: User Stack Trace
I'm sorry to keep beating on this, but I'm still not convinced of what
you're saying...
grundy wrote:
On Thu, Apr 19, 2007 at 09:04:34AM -0700, Stone, Joshua I wrote:
What do you mean by current function? The topmost in the stack? A loop
anywhere in the stack walk will still cause problems.
Current function meaning whatever function made the syscall that gets
probed. If you mess with the return address the syscall will use
(regardless of method) the program will only have one shot at messing
with us. I think most malicious users would prefer multiple shots before
the program crashes.
It's not just the topmost that matters for a stack walk. If I have a
call sequence something like main->A->B->C->sys_open, suppose I corrupt
the return address from A and create a loop. Then I just have to make
sure that I don't return from A, or that I restore the right return info
in A before I return. In the meantime I can repeat my calls to sys_open
hoping that you'll probe it.
Even if the program did crash, there's nothing stopping said user from
wrapping that program in a looping shell script to get multiple shots.
>> [...]
I'm just pointing out that your first access to the value from
nregs->ebp also needs to be protected by _stp_copy_from_user.
ok, I misread that the first time through. The first access to the "value
from nregs->ebp" doesn't leave kernel space. Head actually points
into the regs structure, so it's really printing out the value of
nregs->eax, since it just prints the value it doesn't matter if someone
puts their mom's phone number in there because the first access to the
actual address is through _stp_copy_from_user.
On the first time through, head is the *value* of ebp, not anything
pointing into the nregs structure.
> [...]
> head = (struct frame_head *)nregs->ebp;
>
> if (user_mode_vm(nregs)) {
> do {
> _stp_printf ("[user] <%p>\n", head->ret);
> [...]
The value of nregs->ebp will be the last value that the user had in
there, right? So in your print statement you're dereferencing %ebp to
get ret.
It's a little weird the way it looks with the frame structure in there,
if you look at arch/i386/oprofile/backtrace.c, you'll see where I got
the ideas from. They use a recursive function to do the backtrace. I'm
probably going to go back to that method, I was just having some brain
fade while embedding the code, so I made it an ugly loop instead.
It's not really recursion, but a while loop that calls
dump_user_backtrace. Even the first time through that loop will be
checked with access_ok, which is what your loop is missing in the
translation.
There's also a nice comment in there:
/* frame pointers should strictly progress back up the stack
* (towards higher addresses) */
... which is a more deterministic way to prevent malicious looping.
If you look in the runtime code in stack.c at the end in the old
_stp_ustack_print, they basically tried the same thing, getting the two
quick values available in kernel space. The side effect of using
sysenter is the eip value points to the vdso and has limited value from
an application programmer's point of view.
Yes, and that function is '#if 0'ed. It also makes an unprotected
dereference to esp to get the second address, which is bad.
Josh