blob: efc6a958b71d186a25ee4eadd759f886cf8670f7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/x86_64/ia32/ia32_signal.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
7 * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
8 * 2000-12-* x86-64 compatibility mode signal handling by Andi Kleen
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10
11#include <linux/sched.h>
12#include <linux/mm.h>
13#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/errno.h>
16#include <linux/wait.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/unistd.h>
18#include <linux/stddef.h>
19#include <linux/personality.h>
20#include <linux/compat.h>
Andi Kleen9fbbd4d2007-02-13 13:26:26 +010021#include <linux/binfmts.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <asm/ucontext.h>
23#include <asm/uaccess.h>
24#include <asm/i387.h>
Linus Torvalds1361b832012-02-21 13:19:22 -080025#include <asm/fpu-internal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/ptrace.h>
27#include <asm/ia32_unistd.h>
28#include <asm/user32.h>
29#include <asm/sigcontext32.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <asm/proto.h>
Roland McGrathaf65d642008-01-30 13:30:43 +010031#include <asm/vdso.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080032#include <asm/sigframe.h>
H. Peter Anvinf28f0c22012-02-19 07:38:43 -080033#include <asm/sighandling.h>
Jaswinder Singh Rajput2f06de02008-12-27 21:37:10 +053034#include <asm/sys_ia32.h>
H. Peter Anvin49b8c692012-09-21 17:18:44 -070035#include <asm/smap.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080036
H. Peter Anvinf28f0c22012-02-19 07:38:43 -080037#define FIX_EFLAGS __FIX_EFLAGS
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
40{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080041 int err = 0;
Suresh Siddha0b91f452012-06-14 18:07:15 -070042 bool ia32 = test_thread_flag(TIF_IA32);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010043
44 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 return -EFAULT;
46
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080047 put_user_try {
48 /* If you change siginfo_t structure, please make sure that
49 this code is fixed accordingly.
50 It should never copy any pad contained in the structure
51 to avoid security leaks, but must copy the generic
52 3 ints plus the relevant union member. */
53 put_user_ex(from->si_signo, &to->si_signo);
54 put_user_ex(from->si_errno, &to->si_errno);
55 put_user_ex((short)from->si_code, &to->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080057 if (from->si_code < 0) {
58 put_user_ex(from->si_pid, &to->si_pid);
59 put_user_ex(from->si_uid, &to->si_uid);
60 put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
61 } else {
62 /*
63 * First 32bits of unions are always present:
64 * si_pid === si_band === si_tid === si_addr(LS half)
65 */
66 put_user_ex(from->_sifields._pad[0],
67 &to->_sifields._pad[0]);
68 switch (from->si_code >> 16) {
69 case __SI_FAULT >> 16:
70 break;
Will Drewrya0727e82012-04-12 16:48:00 -050071 case __SI_SYS >> 16:
72 put_user_ex(from->si_syscall, &to->si_syscall);
73 put_user_ex(from->si_arch, &to->si_arch);
74 break;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080075 case __SI_CHLD >> 16:
H. Peter Anvine7084fd2012-03-05 13:40:24 -080076 if (ia32) {
77 put_user_ex(from->si_utime, &to->si_utime);
78 put_user_ex(from->si_stime, &to->si_stime);
79 } else {
80 put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
81 put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
82 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080083 put_user_ex(from->si_status, &to->si_status);
84 /* FALL THROUGH */
85 default:
86 case __SI_KILL >> 16:
87 put_user_ex(from->si_uid, &to->si_uid);
88 break;
89 case __SI_POLL >> 16:
90 put_user_ex(from->si_fd, &to->si_fd);
91 break;
92 case __SI_TIMER >> 16:
93 put_user_ex(from->si_overrun, &to->si_overrun);
94 put_user_ex(ptr_to_compat(from->si_ptr),
95 &to->si_ptr);
96 break;
97 /* This is not generated by the kernel as of now. */
98 case __SI_RT >> 16:
99 case __SI_MESGQ >> 16:
100 put_user_ex(from->si_uid, &to->si_uid);
101 put_user_ex(from->si_int, &to->si_int);
102 break;
103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800105 } put_user_catch(err);
106
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 return err;
108}
109
110int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
111{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800112 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 u32 ptr32;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100114
115 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 return -EFAULT;
117
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800118 get_user_try {
119 get_user_ex(to->si_signo, &from->si_signo);
120 get_user_ex(to->si_errno, &from->si_errno);
121 get_user_ex(to->si_code, &from->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800123 get_user_ex(to->si_pid, &from->si_pid);
124 get_user_ex(to->si_uid, &from->si_uid);
125 get_user_ex(ptr32, &from->si_ptr);
126 to->si_ptr = compat_ptr(ptr32);
127 } get_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
129 return err;
130}
131
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100132asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200134 sigset_t blocked;
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200135 siginitset(&blocked, mask);
Al Viro68f3f162012-05-21 21:42:32 -0400136 return sigsuspend(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137}
138
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100139asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
140 stack_ia32_t __user *uoss_ptr,
141 struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142{
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100143 stack_t uss, uoss;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800144 int ret, err = 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100145 mm_segment_t seg;
146
147 if (uss_ptr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 u32 ptr;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100149
150 memset(&uss, 0, sizeof(stack_t));
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800151 if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)))
152 return -EFAULT;
153
154 get_user_try {
155 get_user_ex(ptr, &uss_ptr->ss_sp);
156 get_user_ex(uss.ss_flags, &uss_ptr->ss_flags);
157 get_user_ex(uss.ss_size, &uss_ptr->ss_size);
158 } get_user_catch(err);
159
160 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 return -EFAULT;
162 uss.ss_sp = compat_ptr(ptr);
163 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100164 seg = get_fs();
165 set_fs(KERNEL_DS);
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200166 ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
167 (stack_t __force __user *) &uoss, regs->sp);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100168 set_fs(seg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 if (ret >= 0 && uoss_ptr) {
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800170 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
171 return -EFAULT;
172
173 put_user_try {
174 put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp);
175 put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags);
176 put_user_ex(uoss.ss_size, &uoss_ptr->ss_size);
177 } put_user_catch(err);
178
179 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 ret = -EFAULT;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100181 }
182 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183}
184
185/*
186 * Do a signal return; undo the signal stack.
187 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800188#define loadsegment_gs(v) load_gs_index(v)
189#define loadsegment_fs(v) loadsegment(fs, v)
190#define loadsegment_ds(v) loadsegment(ds, v)
191#define loadsegment_es(v) loadsegment(es, v)
192
193#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
194#define set_user_seg(seg, v) loadsegment_##seg(v)
195
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800196#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800197 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198}
199
Hiroshi Shimamoto8801ead2009-02-20 19:00:13 -0800200#define GET_SEG(seg) ({ \
201 unsigned short tmp; \
202 get_user_ex(tmp, &sc->seg); \
203 tmp; \
204})
205
206#define COPY_SEG_CPL3(seg) do { \
207 regs->seg = GET_SEG(seg) | 3; \
208} while (0)
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800209
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800210#define RELOAD_SEG(seg) { \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800211 unsigned int pre = GET_SEG(seg); \
212 unsigned int cur = get_user_seg(seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800213 pre |= 3; \
214 if (pre != cur) \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800215 set_user_seg(seg, pre); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800216}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100218static int ia32_restore_sigcontext(struct pt_regs *regs,
219 struct sigcontext_ia32 __user *sc,
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800220 unsigned int *pax)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100221{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800222 unsigned int tmpflags, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700223 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100224 u32 tmp;
225
226 /* Always make any pending restarted system calls return -EINTR */
227 current_thread_info()->restart_block.fn = do_no_restart_syscall;
228
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800229 get_user_try {
230 /*
231 * Reload fs and gs if they have changed in the signal
232 * handler. This does not handle long fs/gs base changes in
233 * the handler, but does not clobber them at least in the
234 * normal case.
235 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800236 RELOAD_SEG(gs);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800237 RELOAD_SEG(fs);
238 RELOAD_SEG(ds);
239 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800241 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
242 COPY(dx); COPY(cx); COPY(ip);
243 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800245 COPY_SEG_CPL3(cs);
246 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800248 get_user_ex(tmpflags, &sc->flags);
249 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
250 /* disable syscall checks */
251 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100252
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800253 get_user_ex(tmp, &sc->fpstate);
254 buf = compat_ptr(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800256 get_user_ex(*pax, &sc->ax);
257 } get_user_catch(err);
258
H. Peter Anvin49b8c692012-09-21 17:18:44 -0700259 err |= restore_xstate_sig(buf, 1);
H. Peter Anvin5e883532012-09-21 12:43:15 -0700260
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262}
263
264asmlinkage long sys32_sigreturn(struct pt_regs *regs)
265{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800266 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100268 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
270 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
271 goto badframe;
272 if (__get_user(set.sig[0], &frame->sc.oldmask)
273 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100274 && __copy_from_user((((char *) &set.sig) + 4),
275 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 sizeof(frame->extramask))))
277 goto badframe;
278
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200279 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100280
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100281 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100283 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
285badframe:
286 signal_fault(regs, frame, "32bit sigreturn");
287 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100288}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
291{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800292 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100294 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 struct pt_regs tregs;
296
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800297 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
299 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
300 goto badframe;
301 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
302 goto badframe;
303
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200304 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100305
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100306 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 goto badframe;
308
309 tregs = *regs;
310 if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
311 goto badframe;
312
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100313 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100316 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100318}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
320/*
321 * Set up a signal frame.
322 */
323
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100324static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700325 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100326 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800328 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800330 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800331 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
332 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
333 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
334 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800336 put_user_ex(regs->di, &sc->di);
337 put_user_ex(regs->si, &sc->si);
338 put_user_ex(regs->bp, &sc->bp);
339 put_user_ex(regs->sp, &sc->sp);
340 put_user_ex(regs->bx, &sc->bx);
341 put_user_ex(regs->dx, &sc->dx);
342 put_user_ex(regs->cx, &sc->cx);
343 put_user_ex(regs->ax, &sc->ax);
Srikar Dronamraju51e7dc72012-03-12 14:55:55 +0530344 put_user_ex(current->thread.trap_nr, &sc->trapno);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800345 put_user_ex(current->thread.error_code, &sc->err);
346 put_user_ex(regs->ip, &sc->ip);
347 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
348 put_user_ex(regs->flags, &sc->flags);
349 put_user_ex(regs->sp, &sc->sp_at_signal);
350 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800352 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800354 /* non-iBCS2 extensions.. */
355 put_user_ex(mask, &sc->oldmask);
356 put_user_ex(current->thread.cr2, &sc->cr2);
357 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
359 return err;
360}
361
362/*
363 * Determine which stack to use..
364 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100365static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700366 size_t frame_size,
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200367 void __user **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100369 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100372 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374 /* This is the X/Open sanctioned signal stack switching. */
375 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100376 if (sas_ss_flags(sp) == 0)
377 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 }
379
380 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800381 else if ((regs->ss & 0xffff) != __USER32_DS &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100383 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100384 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700386 if (used_math()) {
Suresh Siddha72a671c2012-07-24 16:05:29 -0700387 unsigned long fx_aligned, math_size;
388
389 sp = alloc_mathframe(sp, 1, &fx_aligned, &math_size);
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200390 *fpstate = (struct _fpstate_ia32 __user *) sp;
Suresh Siddha72a671c2012-07-24 16:05:29 -0700391 if (save_xstate_sig(*fpstate, (void __user *)fx_aligned,
392 math_size) < 0)
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800393 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700394 }
395
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100396 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200397 /* Align the stack pointer according to the i386 ABI,
398 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100399 sp = ((sp + 4) & -16ul) - 4;
400 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401}
402
Roland McGrath0928d6e2005-06-23 00:08:37 -0700403int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100404 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800406 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100407 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700409 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100411 /* copy_to_user optimizes that into a single 8 byte store */
412 static const struct {
413 u16 poplmovl;
414 u32 val;
415 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100416 } __attribute__((packed)) code = {
417 0xb858, /* popl %eax ; movl $...,%eax */
418 __NR_ia32_sigreturn,
419 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100420 };
421
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700422 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
424 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700425 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700427 if (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700428 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700430 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700431 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700434 if (__copy_to_user(frame->extramask, &set->sig[1],
435 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700436 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
Roland McGrathaf65d642008-01-30 13:30:43 +0100439 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100440 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100441 } else {
442 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700443 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100444 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
445 sigreturn);
446 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100447 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100448 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100449
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800450 put_user_try {
451 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
452
453 /*
454 * These are actually not used anymore, but left because some
455 * gdb versions depend on them as a marker.
456 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200457 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800458 } put_user_catch(err);
459
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700461 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
463 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100464 regs->sp = (unsigned long) frame;
465 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Andi Kleen536e3ee2006-09-26 10:52:41 +0200467 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100468 regs->ax = sig;
469 regs->dx = 0;
470 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200471
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700472 loadsegment(ds, __USER32_DS);
473 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100475 regs->cs = __USER32_CS;
476 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477
Andi Kleen1d001df2006-09-26 10:52:26 +0200478 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479}
480
Roland McGrath0928d6e2005-06-23 00:08:37 -0700481int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100482 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800484 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100485 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700487 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100489 /* __copy_to_user optimizes that into a single 8 byte store */
490 static const struct {
491 u8 movl;
492 u32 val;
493 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800494 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100495 } __attribute__((packed)) code = {
496 0xb8,
497 __NR_ia32_rt_sigreturn,
498 0x80cd,
499 0,
500 };
501
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700502 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700505 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800507 put_user_try {
508 put_user_ex(sig, &frame->sig);
509 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
510 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800512 /* Create the ucontext. */
513 if (cpu_has_xsave)
514 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
515 else
516 put_user_ex(0, &frame->uc.uc_flags);
517 put_user_ex(0, &frame->uc.uc_link);
518 put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
519 put_user_ex(sas_ss_flags(regs->sp),
520 &frame->uc.uc_stack.ss_flags);
521 put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800523 if (ka->sa.sa_flags & SA_RESTORER)
524 restorer = ka->sa.sa_restorer;
525 else
526 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
527 rt_sigreturn);
528 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800530 /*
531 * Not actually used anymore, but left because some gdb
532 * versions need it.
533 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200534 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800535 } put_user_catch(err);
536
H. Peter Anvin5e883532012-09-21 12:43:15 -0700537 err |= copy_siginfo_to_user32(&frame->info, info);
538 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
539 regs, set->sig[0]);
540 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700543 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100546 regs->sp = (unsigned long) frame;
547 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500549 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100550 regs->ax = sig;
551 regs->dx = (unsigned long) &frame->info;
552 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500553
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700554 loadsegment(ds, __USER32_DS);
555 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100556
557 regs->cs = __USER32_CS;
558 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
Andi Kleen1d001df2006-09-26 10:52:26 +0200560 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561}