linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: dvorak <dvorak@xs4all.nl>
To: "Richard B. Johnson" <root@chaos.analogic.com>
Cc: linux-kernel@vger.kernel.org
Subject: Re: Syscall changes registers beyond %eax, on linux-i386
Date: Thu, 19 Sep 2002 19:59:41 +0200	[thread overview]
Message-ID: <20020919175941.GA7851@xs4all.nl> (raw)
In-Reply-To: <Pine.LNX.3.95.1020919131927.15141A-100000@chaos.analogic.com>

[-- Attachment #1: Type: text/plain, Size: 3873 bytes --]

On Thu, Sep 19, 2002 at 01:22:35PM -0400, Richard B. Johnson wrote:
> On Thu, 19 Sep 2002, Brian Gerst wrote:
> 
> > Richard B. Johnson wrote:
> > > On Thu, 19 Sep 2002, dvorak wrote:
> > > 
> > > 
> > >>Hi,
> > >>
> > >>recently i came across a situation were on linux-i386 not only %eax was
> > >>altered after a syscall but also %ebx. I tracked this problem down, to
> > >>gcc re-using a variable passed to a function.
> > >>
> > >>This was found on a debian system with a 2.4.17 kernel compiled with gcc
> > >>2.95.2 and verified on another system, kernel 2.4.18 compiled with 2.95.4 
> > >>Attached is small program to test for this 'bug'
> > >>
<SNIP part of the explanation>

> > >>It seems that gcc in certain cases optimizes in such a way that it changes
> > >>the variable ufds as placed on the stack directly. Which results in saved(ebx)
> > >>being overwritten and thus in a changed %ebx on return from the system call.
> > >>
> > > 
> > > 
> > > The 'C' compiler must make room on the stack for any local
> > > variables except register types. If it was doing as you state, you
> > > couldn't even execute a "hello world" program. Further, the local
> > > variables are after the return address. It would screw up the return
> > > address and you'd go off into hyper-space upon return.

The problem is it uses one of the _arguments_ passed to the function, 
that argument gets modified, normally this happens on a copy, but there
is no 'garantue' that is doesn't modify the original argument as
putted on the stack by the calling function.

> > > No. Various 'C' implementers have standardized calling methods even
> > > though it's not part of the 'C' standard. gcc and others assume that
> > > a called procedure is not going to change any segments or index registers.
> > > There are various optimization things, like "-fcaller-saves" where the
> > > called procedure can destroy anything. You may be using something that
> > > was wrongly compiled using that switch.
This is not what happens here, what happens is that one of the _arguments_
placed on the stack is being modified, normally a calling function discards
these values after use (addl $0x10, %esp or similar) but in this case they
are reused. (in the RESTORE_ALL call)

> > 
> > 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.
> > 
and only with _some_ compiler + kernel combinations.

> 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.
I putted in some assembler code in my original post that uses the sys_poll
syscall of which i _know_ it modifies one of it's arguments, to be more
specific, it's first argument, which is %ebx on passing in:
asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
....
      for(i=0; i < (int)nfds; i++, ufds++, fds1++) {
....

and in fact we saw that the change in %ebx is proportional to the nfds
as passed to sys_poll.

now however for sys_ioctl:
it's first argument, fd (%ebx on passing) is never modifed in the code 
nowhere is there an fd++ or similar, so again this 'example' of yours is
flawed.

gtx.
   dvorak


P.S. i think my original was quite clear and INCLUDED example code that can
easily be checked by someone who reads asm, i attach an extra copy which
explains all the asm in there for easier reference.

[-- Attachment #2: reg-bug.c --]
[-- Type: text/plain, Size: 2476 bytes --]

/*
 * usage is easy, though not very friendly:
 * gcc reg-bug.c
 * ./a.out | od -tx4
 * <ENTER>
 * if the values outputted by hexdump are different the 'bug' is present
 * else the bug is not present
 * on a system without the bug:

dvorak$ dmesg | head -1
Linux version 2.2.21 (kernel@debian) (gcc version 2.95.4 20011002 (Debian prerelease)) #6 Sat Sep 7 22:48:42 CEST 2002
dvorak$ gcc reg-bug.c
dvorak$ ./a.out | od -tx4

0000000 bff7de6c bff7de6c
 
 * on a 'buggy' system:
 *

(m4xx) dmesg | head -1
(m4xx) Linux version 2.4.18 (maxx@meuuh) (gcc version 2.95.4 20011002 (Debian
+prerelease)) #2 Mon Jul 29 17:01:30 CEST 2002
(m4xx) $ gcc reg-bug.c
(m4xx) $ ./a.out | od -tx4
(m4xx) 0000000 bffffdcc bffffdbc

 */
int main(void)
{
    __asm__("
        pushl   $0x00010001     # this is events and revents
        pushl   $0x0            # fd 0
        pushl   $0x00010001     # again events and revents
        pushl   $0x1            # fd 1
        movl    %esp, %ebx      # %ebx now contains a pointer to the
                                # pollfd structure i setted up,
                                # note that only pushes occur
                                # below so this structures stays on the stack
        pushl   %ebx            # we pushl %ebx to compare it later
        movl    $0x2, %ecx      # 2 = number of fd's
        movl    $0xa8, %eax     # __NR_sys_poll
        movl    $(-1), %edx     # no timeout
        int     $0x80           # call kernel
                                # sys_poll(%ebx, %ecx, %edx)
                                #  %ebx == ufds (address of the pollfd structs)o                                #  %ecx == num fd's (2)
                                #  %edx == timeout (-1)
        pushl   %ebx            # we push the returned %ebx on the stack
                                # as well
        movl    %esp, %ecx      # %ecx is now pointer to the 2 saved %ebx's
        movl    $0x08, %edx     # %edx = 8
        movl    $0x04, %eax     # %eax = 4 == __NR_sys_write
        movl    $0x01, %ebx     # %ebx = 1 == fd
        int     $0x80           # call kernel
                                # sys_write(%ebx, %ecx, %edx)
                                #  %ebx = fd (1)
                                #  %ecx = buf (pointer to the 2 saved %ebx's)   
                                #  %edx = len (8)
        movl    $0x01, %eax     # and an sys_exit(0);
        xorl    %ebx, %ebx
        int     $0x80
   ");
}

  parent reply	other threads:[~2002-09-19 17:54 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-09-19 14:45 Syscall changes registers beyond %eax, on linux-i386 dvorak
2002-09-19 16:11 ` Richard B. Johnson
2002-09-19 17:09   ` Brian Gerst
2002-09-19 17:22     ` Richard B. Johnson
2002-09-19 17:51       ` Brian Gerst
2002-09-19 18:30         ` Richard B. Johnson
2002-09-19 17:59       ` dvorak [this message]
2002-09-19 18:32         ` Richard B. Johnson
2002-09-19 17:44 Petr Vandrovec
2002-09-19 18:04 ` Brian Gerst
2002-09-19 18:30   ` Richard Henderson
2002-09-19 18:51     ` Brian Gerst
2002-09-19 18:57       ` Richard Henderson
2002-09-19 19:40         ` Richard B. Johnson
2002-09-19 19:41           ` Richard Henderson
2002-09-19 19:53             ` Richard B. Johnson
2002-09-19 22:46               ` J.A. Magallon
2002-09-20 12:27                 ` Richard B. Johnson
2002-09-20 17:16                   ` Richard Henderson
2002-09-22  1:33               ` Pavel Machek
2002-09-23 13:11                 ` Richard B. Johnson
2002-09-23 18:31                   ` Pavel Machek
2002-09-19 19:18       ` Richard B. Johnson
2002-09-19 19:24   ` Daniel Jacobowitz
2002-09-19 20:25     ` Mikael Pettersson
2002-09-20  8:32       ` george anzinger
2002-09-21  6:19         ` Richard Henderson
2002-09-21  8:09           ` george anzinger
2002-09-21 15:08             ` Richard Henderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20020919175941.GA7851@xs4all.nl \
    --to=dvorak@xs4all.nl \
    --cc=linux-kernel@vger.kernel.org \
    --cc=root@chaos.analogic.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).