This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]