summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2004-10-16 19:20:30 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-10-16 19:20:30 -0700
commitc5cada670bf08d89870dd43ea25419f6ffb27c33 (patch)
tree18fafc925781ad275ca6b161e4615df2e0b2ff70
parent74a82aa978123ad278514ee5553343ff7008b5f7 (diff)
[PATCH] tailcall prevention in sys_wait4() and sys_waitid()
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>
-rw-r--r--include/asm-i386/linkage.h4
-rw-r--r--include/linux/linkage.h4
-rw-r--r--kernel/exit.c16
3 files changed, 22 insertions, 2 deletions
diff --git a/include/asm-i386/linkage.h b/include/asm-i386/linkage.h
index e48009fd93c7..af3d8571c5c7 100644
--- a/include/asm-i386/linkage.h
+++ b/include/asm-i386/linkage.h
@@ -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"
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index 09955c0ce848..338f7795d8a0 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -14,6 +14,10 @@
#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"
diff --git a/kernel/exit.c b/kernel/exit.c
index 6860b509dd11..6ec1f96fa92b 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -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