aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2008-04-10 18:37:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-10 20:28:26 -0400
commit54a015104136974262afa4b8ddd943ea70dec8a2 (patch)
tree713f0c1f4d0afe62e5c568a424e309f70388cf7f
parent783e391b7b5b273cd20856d8f6f4878da8ec31b3 (diff)
asmlinkage_protect replaces prevent_tail_call
The prevent_tail_call() macro works around the problem of the compiler clobbering argument words on the stack, which for asmlinkage functions is the caller's (user's) struct pt_regs. The tail/sibling-call optimization is not the only way that the compiler can decide to use stack argument words as scratch space, which we have to prevent. Other optimizations can do it too. Until we have new compiler support to make "asmlinkage" binding on the compiler's own use of the stack argument frame, we have work around all the manifestations of this issue that crop up. More cases seem to be prevented by also keeping the incoming argument variables live at the end of the function. This makes their original stack slots attractive places to leave those variables, so the compiler tends not clobber them for something else. It's still no guarantee, but it handles some observed cases that prevent_tail_call() did not. Signed-off-by: Roland McGrath <roland@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/x86/kernel/tls.c4
-rw-r--r--fs/open.c8
-rw-r--r--include/asm-x86/linkage.h24
-rw-r--r--include/linux/linkage.h4
-rw-r--r--kernel/exit.c4
-rw-r--r--kernel/uid16.c22
6 files changed, 44 insertions, 22 deletions
diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c
index 022bcaa3b42e..ab6bf375a307 100644
--- a/arch/x86/kernel/tls.c
+++ b/arch/x86/kernel/tls.c
@@ -92,7 +92,7 @@ int do_set_thread_area(struct task_struct *p, int idx,
92asmlinkage int sys_set_thread_area(struct user_desc __user *u_info) 92asmlinkage int sys_set_thread_area(struct user_desc __user *u_info)
93{ 93{
94 int ret = do_set_thread_area(current, -1, u_info, 1); 94 int ret = do_set_thread_area(current, -1, u_info, 1);
95 prevent_tail_call(ret); 95 asmlinkage_protect(1, ret, u_info);
96 return ret; 96 return ret;
97} 97}
98 98
@@ -142,7 +142,7 @@ int do_get_thread_area(struct task_struct *p, int idx,
142asmlinkage int sys_get_thread_area(struct user_desc __user *u_info) 142asmlinkage int sys_get_thread_area(struct user_desc __user *u_info)
143{ 143{
144 int ret = do_get_thread_area(current, -1, u_info); 144 int ret = do_get_thread_area(current, -1, u_info);
145 prevent_tail_call(ret); 145 asmlinkage_protect(1, ret, u_info);
146 return ret; 146 return ret;
147} 147}
148 148
diff --git a/fs/open.c b/fs/open.c
index a4b12022edaa..3fa4e4ffce4c 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -335,7 +335,7 @@ asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length)
335{ 335{
336 long ret = do_sys_ftruncate(fd, length, 1); 336 long ret = do_sys_ftruncate(fd, length, 1);
337 /* avoid REGPARM breakage on x86: */ 337 /* avoid REGPARM breakage on x86: */
338 prevent_tail_call(ret); 338 asmlinkage_protect(2, ret, fd, length);
339 return ret; 339 return ret;
340} 340}
341 341
@@ -350,7 +350,7 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
350{ 350{
351 long ret = do_sys_ftruncate(fd, length, 0); 351 long ret = do_sys_ftruncate(fd, length, 0);
352 /* avoid REGPARM breakage on x86: */ 352 /* avoid REGPARM breakage on x86: */
353 prevent_tail_call(ret); 353 asmlinkage_protect(2, ret, fd, length);
354 return ret; 354 return ret;
355} 355}
356#endif 356#endif
@@ -1067,7 +1067,7 @@ asmlinkage long sys_open(const char __user *filename, int flags, int mode)
1067 1067
1068 ret = do_sys_open(AT_FDCWD, filename, flags, mode); 1068 ret = do_sys_open(AT_FDCWD, filename, flags, mode);
1069 /* avoid REGPARM breakage on x86: */ 1069 /* avoid REGPARM breakage on x86: */
1070 prevent_tail_call(ret); 1070 asmlinkage_protect(3, ret, filename, flags, mode);
1071 return ret; 1071 return ret;
1072} 1072}
1073 1073
@@ -1081,7 +1081,7 @@ asmlinkage long sys_openat(int dfd, const char __user *filename, int flags,
1081 1081
1082 ret = do_sys_open(dfd, filename, flags, mode); 1082 ret = do_sys_open(dfd, filename, flags, mode);
1083 /* avoid REGPARM breakage on x86: */ 1083 /* avoid REGPARM breakage on x86: */
1084 prevent_tail_call(ret); 1084 asmlinkage_protect(4, ret, dfd, filename, flags, mode);
1085 return ret; 1085 return ret;
1086} 1086}
1087 1087
diff --git a/include/asm-x86/linkage.h b/include/asm-x86/linkage.h
index 31739c7d66a9..d605eeba0f70 100644
--- a/include/asm-x86/linkage.h
+++ b/include/asm-x86/linkage.h
@@ -8,12 +8,34 @@
8 8
9#ifdef CONFIG_X86_32 9#ifdef CONFIG_X86_32
10#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0))) 10#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
11#define prevent_tail_call(ret) __asm__ ("" : "=r" (ret) : "0" (ret))
12/* 11/*
13 * For 32-bit UML - mark functions implemented in assembly that use 12 * For 32-bit UML - mark functions implemented in assembly that use
14 * regparm input parameters: 13 * regparm input parameters:
15 */ 14 */
16#define asmregparm __attribute__((regparm(3))) 15#define asmregparm __attribute__((regparm(3)))
16
17#define asmlinkage_protect(n, ret, args...) \
18 __asmlinkage_protect##n(ret, ##args)
19#define __asmlinkage_protect_n(ret, args...) \
20 __asm__ __volatile__ ("" : "=r" (ret) : "0" (ret), ##args)
21#define __asmlinkage_protect0(ret) \
22 __asmlinkage_protect_n(ret)
23#define __asmlinkage_protect1(ret, arg1) \
24 __asmlinkage_protect_n(ret, "g" (arg1))
25#define __asmlinkage_protect2(ret, arg1, arg2) \
26 __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2))
27#define __asmlinkage_protect3(ret, arg1, arg2, arg3) \
28 __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3))
29#define __asmlinkage_protect4(ret, arg1, arg2, arg3, arg4) \
30 __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3), \
31 "g" (arg4))
32#define __asmlinkage_protect5(ret, arg1, arg2, arg3, arg4, arg5) \
33 __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3), \
34 "g" (arg4), "g" (arg5))
35#define __asmlinkage_protect6(ret, arg1, arg2, arg3, arg4, arg5, arg6) \
36 __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3), \
37 "g" (arg4), "g" (arg5), "g" (arg6))
38
17#endif 39#endif
18 40
19#ifdef CONFIG_X86_ALIGNMENT_16 41#ifdef CONFIG_X86_ALIGNMENT_16
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index 0592936344c4..fe2a39c489b6 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -17,8 +17,8 @@
17# define asmregparm 17# define asmregparm
18#endif 18#endif
19 19
20#ifndef prevent_tail_call 20#ifndef asmlinkage_protect
21# define prevent_tail_call(ret) do { } while (0) 21# define asmlinkage_protect(n, ret, args...) do { } while (0)
22#endif 22#endif
23 23
24#ifndef __ALIGN 24#ifndef __ALIGN
diff --git a/kernel/exit.c b/kernel/exit.c
index 53872bf993fa..073005b1cfb2 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -1608,7 +1608,7 @@ asmlinkage long sys_waitid(int which, pid_t upid,
1608 put_pid(pid); 1608 put_pid(pid);
1609 1609
1610 /* avoid REGPARM breakage on x86: */ 1610 /* avoid REGPARM breakage on x86: */
1611 prevent_tail_call(ret); 1611 asmlinkage_protect(5, ret, which, upid, infop, options, ru);
1612 return ret; 1612 return ret;
1613} 1613}
1614 1614
@@ -1640,7 +1640,7 @@ asmlinkage long sys_wait4(pid_t upid, int __user *stat_addr,
1640 put_pid(pid); 1640 put_pid(pid);
1641 1641
1642 /* avoid REGPARM breakage on x86: */ 1642 /* avoid REGPARM breakage on x86: */
1643 prevent_tail_call(ret); 1643 asmlinkage_protect(4, ret, upid, stat_addr, options, ru);
1644 return ret; 1644 return ret;
1645} 1645}
1646 1646
diff --git a/kernel/uid16.c b/kernel/uid16.c
index dd308ba4e03b..3e41c1673e2f 100644
--- a/kernel/uid16.c
+++ b/kernel/uid16.c
@@ -21,7 +21,7 @@ asmlinkage long sys_chown16(const char __user * filename, old_uid_t user, old_gi
21{ 21{
22 long ret = sys_chown(filename, low2highuid(user), low2highgid(group)); 22 long ret = sys_chown(filename, low2highuid(user), low2highgid(group));
23 /* avoid REGPARM breakage on x86: */ 23 /* avoid REGPARM breakage on x86: */
24 prevent_tail_call(ret); 24 asmlinkage_protect(3, ret, filename, user, group);
25 return ret; 25 return ret;
26} 26}
27 27
@@ -29,7 +29,7 @@ asmlinkage long sys_lchown16(const char __user * filename, old_uid_t user, old_g
29{ 29{
30 long ret = sys_lchown(filename, low2highuid(user), low2highgid(group)); 30 long ret = sys_lchown(filename, low2highuid(user), low2highgid(group));
31 /* avoid REGPARM breakage on x86: */ 31 /* avoid REGPARM breakage on x86: */
32 prevent_tail_call(ret); 32 asmlinkage_protect(3, ret, filename, user, group);
33 return ret; 33 return ret;
34} 34}
35 35
@@ -37,7 +37,7 @@ asmlinkage long sys_fchown16(unsigned int fd, old_uid_t user, old_gid_t group)
37{ 37{
38 long ret = sys_fchown(fd, low2highuid(user), low2highgid(group)); 38 long ret = sys_fchown(fd, low2highuid(user), low2highgid(group));
39 /* avoid REGPARM breakage on x86: */ 39 /* avoid REGPARM breakage on x86: */
40 prevent_tail_call(ret); 40 asmlinkage_protect(3, ret, fd, user, group);
41 return ret; 41 return ret;
42} 42}
43 43
@@ -45,7 +45,7 @@ asmlinkage long sys_setregid16(old_gid_t rgid, old_gid_t egid)
45{ 45{
46 long ret = sys_setregid(low2highgid(rgid), low2highgid(egid)); 46 long ret = sys_setregid(low2highgid(rgid), low2highgid(egid));
47 /* avoid REGPARM breakage on x86: */ 47 /* avoid REGPARM breakage on x86: */
48 prevent_tail_call(ret); 48 asmlinkage_protect(2, ret, rgid, egid);
49 return ret; 49 return ret;
50} 50}
51 51
@@ -53,7 +53,7 @@ asmlinkage long sys_setgid16(old_gid_t gid)
53{ 53{
54 long ret = sys_setgid(low2highgid(gid)); 54 long ret = sys_setgid(low2highgid(gid));
55 /* avoid REGPARM breakage on x86: */ 55 /* avoid REGPARM breakage on x86: */
56 prevent_tail_call(ret); 56 asmlinkage_protect(1, ret, gid);
57 return ret; 57 return ret;
58} 58}
59 59
@@ -61,7 +61,7 @@ asmlinkage long sys_setreuid16(old_uid_t ruid, old_uid_t euid)
61{ 61{
62 long ret = sys_setreuid(low2highuid(ruid), low2highuid(euid)); 62 long ret = sys_setreuid(low2highuid(ruid), low2highuid(euid));
63 /* avoid REGPARM breakage on x86: */ 63 /* avoid REGPARM breakage on x86: */
64 prevent_tail_call(ret); 64 asmlinkage_protect(2, ret, ruid, euid);
65 return ret; 65 return ret;
66} 66}
67 67
@@ -69,7 +69,7 @@ asmlinkage long sys_setuid16(old_uid_t uid)
69{ 69{
70 long ret = sys_setuid(low2highuid(uid)); 70 long ret = sys_setuid(low2highuid(uid));
71 /* avoid REGPARM breakage on x86: */ 71 /* avoid REGPARM breakage on x86: */
72 prevent_tail_call(ret); 72 asmlinkage_protect(1, ret, uid);
73 return ret; 73 return ret;
74} 74}
75 75
@@ -78,7 +78,7 @@ asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid)
78 long ret = sys_setresuid(low2highuid(ruid), low2highuid(euid), 78 long ret = sys_setresuid(low2highuid(ruid), low2highuid(euid),
79 low2highuid(suid)); 79 low2highuid(suid));
80 /* avoid REGPARM breakage on x86: */ 80 /* avoid REGPARM breakage on x86: */
81 prevent_tail_call(ret); 81 asmlinkage_protect(3, ret, ruid, euid, suid);
82 return ret; 82 return ret;
83} 83}
84 84
@@ -98,7 +98,7 @@ asmlinkage long sys_setresgid16(old_gid_t rgid, old_gid_t egid, old_gid_t sgid)
98 long ret = sys_setresgid(low2highgid(rgid), low2highgid(egid), 98 long ret = sys_setresgid(low2highgid(rgid), low2highgid(egid),
99 low2highgid(sgid)); 99 low2highgid(sgid));
100 /* avoid REGPARM breakage on x86: */ 100 /* avoid REGPARM breakage on x86: */
101 prevent_tail_call(ret); 101 asmlinkage_protect(3, ret, rgid, egid, sgid);
102 return ret; 102 return ret;
103} 103}
104 104
@@ -117,7 +117,7 @@ asmlinkage long sys_setfsuid16(old_uid_t uid)
117{ 117{
118 long ret = sys_setfsuid(low2highuid(uid)); 118 long ret = sys_setfsuid(low2highuid(uid));
119 /* avoid REGPARM breakage on x86: */ 119 /* avoid REGPARM breakage on x86: */
120 prevent_tail_call(ret); 120 asmlinkage_protect(1, ret, uid);
121 return ret; 121 return ret;
122} 122}
123 123
@@ -125,7 +125,7 @@ asmlinkage long sys_setfsgid16(old_gid_t gid)
125{ 125{
126 long ret = sys_setfsgid(low2highgid(gid)); 126 long ret = sys_setfsgid(low2highgid(gid));
127 /* avoid REGPARM breakage on x86: */ 127 /* avoid REGPARM breakage on x86: */
128 prevent_tail_call(ret); 128 asmlinkage_protect(1, ret, gid);
129 return ret; 129 return ret;
130} 130}
131 131