Re: Syscall changes registers beyond %eax, on linux-i386

Brian Gerst
2002-09-19T17:46:31Z

Richard B. Johnson wrote:
> On Thu, 19 Sep 2002, Brian Gerst wrote:
>>Richard B. Johnson wrote:
>>>There is a bug in some other code. Try this. It will show
>>>that ebx is not being killed in a syscall. You can prove
>>>that this code works by changing ebx to eax, which will
>>>get destroyed and print "Broken" before exit.
>>
>>The bug is only with _some_ syscalls, and getpid() is not one of them,
>>so your example is flawed. It happens when a syscall modifies one of
>>it's parameter values. The solution is to assign the parameter to a
>>local variable before modifying it.
>>
>
>
> Well which one? Here is an ioctl(). It certainly modifies one
> of its parameter values.
>
> #include <stdio.h>
> #include <unistd.h>
> #include <sys/ioctl.h>
> #include <termios.h>
>
> void barf(void);
> void barf()
> {
> puts("Broken\n");
> exit(0);
> }
> int main()
> {
> struct termios t;
>
> __asm__ __volatile__("movl $0xdeadface, %ebx\n");
> (void)ioctl(0, TCGETS, &t);
> (void)getpid();
> __asm__ __volatile__("cmpl $0xdeadface, %ebx\n"
> "jnz barf\n");
>
> return 0;
> }
>
>
> Until you can show the syscall that doesn't follow the correct
> rules, then my example is not flawed. In fact a modified example can
> be used to find any broken calls.

Well the original poster gave one valid example: sys_poll(). We're not
talking about it modifying userspace though a pointer. We're talking
about it taking it's parameter on the kernel stack (which is really the
pt_regs structure saved from user space) and modifying it. Which then
gets restored to the user registers upon syscall exit.

This is how the kernel stack looks like inside a syscall (x86):
OLDSS
OLDESP
EFLAGS
CS
EIP
ORIG_EAX
ES
DS
EAX <- syscall number
EBP <- syscall arg6
EDI <- syscall arg5
ESI <- syscall arg4
EDX <- syscall arg3
ECX <- syscall arg2
EBX <- syscall arg1
(return address)
(local variables)

Everything above the return address is the pt_regs struct that gets
restored to user space. If the syscall modifies any of its args (*not
memory pointed to by the args*), they get written back to the stack in
the pt_regs area, and then get restored to userspace modified.
Understand now?

--
Brian Gerst