]> git.hungrycats.org Git - linux/commitdiff
[PATCH] tailcall prevention in sys_wait4() and sys_waitid()
authorIngo Molnar <mingo@elte.hu>
Sun, 17 Oct 2004 02:20:30 +0000 (19:20 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Sun, 17 Oct 2004 02:20:30 +0000 (19:20 -0700)
A hack to prevent the compiler from generatin tailcalls in these two
functions.

With CONFIG_REGPARM=y, the tailcalled code ends up stomping on the
syscall's argument frame which corrupts userspace's registers.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
include/asm-i386/linkage.h
include/linux/linkage.h
kernel/exit.c

index e48009fd93c73a1334eeec7bf103c9fd68a3fe0d..af3d8571c5c7c06a38967b1559d4a40ca07993e7 100644 (file)
@@ -5,6 +5,10 @@
 #define FASTCALL(x)    x __attribute__((regparm(3)))
 #define fastcall       __attribute__((regparm(3)))
 
+#ifdef CONFIG_REGPARM
+# define prevent_tail_call(ret) __asm__ ("" : "=r" (ret) : "0" (ret))
+#endif
+
 #ifdef CONFIG_X86_ALIGNMENT_16
 #define __ALIGN .align 16,0x90
 #define __ALIGN_STR ".align 16,0x90"
index 09955c0ce848a8ac23eb4b6d261221f18c0a427f..338f7795d8a071d63b05969505b6fe9894eafc46 100644 (file)
 #define asmlinkage CPP_ASMLINKAGE
 #endif
 
+#ifndef prevent_tail_call
+# define prevent_tail_call(ret) do { } while (0)
+#endif
+
 #ifndef __ALIGN
 #define __ALIGN                .align 4,0x90
 #define __ALIGN_STR    ".align 4,0x90"
index 6860b509dd11f8bb2dcac5706d63d768ebbf2132..6ec1f96fa92b6e4a3daaf1e698ae6ff30a7b2051 100644 (file)
@@ -1376,6 +1376,8 @@ asmlinkage long sys_waitid(int which, pid_t pid,
                           struct siginfo __user *infop, int options,
                           struct rusage __user *ru)
 {
+       long ret;
+
        if (options & ~(WNOHANG|WNOWAIT|WEXITED|WSTOPPED|WCONTINUED))
                return -EINVAL;
        if (!(options & (WEXITED|WSTOPPED|WCONTINUED)))
@@ -1398,15 +1400,25 @@ asmlinkage long sys_waitid(int which, pid_t pid,
                return -EINVAL;
        }
 
-       return do_wait(pid, options, infop, NULL, ru);
+       ret = do_wait(pid, options, infop, NULL, ru);
+
+       /* avoid REGPARM breakage on x86: */
+       prevent_tail_call(ret);
+       return ret;
 }
 
 asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr,
                          int options, struct rusage __user *ru)
 {
+       long ret;
+
        if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
                return -EINVAL;
-       return do_wait(pid, options | WEXITED, NULL, stat_addr, ru);
+       ret = do_wait(pid, options | WEXITED, NULL, stat_addr, ru);
+
+       /* avoid REGPARM breakage on x86: */
+       prevent_tail_call(ret);
+       return ret;
 }
 
 #ifdef __ARCH_WANT_SYS_WAITPID