sys_poll: fix incorrect type for 'timeout' parameter
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 22 Feb 2012 01:24:20 +0000 (17:24 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 22 Feb 2012 01:24:20 +0000 (17:24 -0800)
The 'poll()' system call timeout parameter is supposed to be 'int', not
'long'.

Now, the reason this matters is that right now 32-bit compat mode is
broken on at least x86-64, because the 32-bit code just calls
'sys_poll()' directly on x86-64, and the 32-bit argument will have been
zero-extended, turning a signed 'int' into a large unsigned 'long'
value.

We could just introduce a 'compat_sys_poll()' function for this, and
that may eventually be what we have to do, but since the actual standard
poll() semantics is *supposed* to be 'int', and since at least on x86-64
glibc sign-extends the argument before invocing the system call (so
nobody can actually use a 64-bit timeout value in user space _anyway_,
even in 64-bit binaries), the simpler solution would seem to be to just
fix the definition of the system call to match what it should have been
from the very start.

If it turns out that somebody somehow circumvents the user-level libc
64-bit sign extension and actually uses a large unsigned 64-bit timeout
despite that not being how poll() is supposed to work, we will need to
do the compat_sys_poll() approach.

Reported-by: Thomas Meyer <thomas@m3y3r.de>
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/s390/kernel/compat_wrapper.S
fs/select.c
include/linux/syscalls.h

index 18c51df9fe06c5ed98f785fb6af86655c025e887..ff605a39cf435661a6ba6ab5dee05544239fae6b 100644 (file)
@@ -662,7 +662,7 @@ ENTRY(sys32_getresuid16_wrapper)
 ENTRY(sys32_poll_wrapper)
        llgtr   %r2,%r2                 # struct pollfd *
        llgfr   %r3,%r3                 # unsigned int
-       lgfr    %r4,%r4                 # long
+       lgfr    %r4,%r4                 # int
        jg      sys_poll                # branch to system call
 
 ENTRY(sys32_setresgid16_wrapper)
index d33418fdc858fbbe7f929d692dae1533c2e9a271..e782258d0de3cec01c6767aa5cb2b2684e1077ac 100644 (file)
@@ -912,7 +912,7 @@ static long do_restart_poll(struct restart_block *restart_block)
 }
 
 SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,
-               long, timeout_msecs)
+               int, timeout_msecs)
 {
        struct timespec end_time, *to = NULL;
        int ret;
index 515669fa3c1d97e0067c6ef404c5263458251810..8ec1153ff57b9c3c4d4b6c7360fd01bbdaebbc2c 100644 (file)
@@ -624,7 +624,7 @@ asmlinkage long sys_socketpair(int, int, int, int __user *);
 asmlinkage long sys_socketcall(int call, unsigned long __user *args);
 asmlinkage long sys_listen(int, int);
 asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
-                               long timeout);
+                               int timeout);
 asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp,
                        fd_set __user *exp, struct timeval __user *tvp);
 asmlinkage long sys_old_select(struct sel_arg_struct __user *arg);