blob: 15fdb3f57d8c0abdd2ca9e89be73c4631d97086a [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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139/*
140 * Do a signal return; undo the signal stack.
141 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800142#define loadsegment_gs(v) load_gs_index(v)
143#define loadsegment_fs(v) loadsegment(fs, v)
144#define loadsegment_ds(v) loadsegment(ds, v)
145#define loadsegment_es(v) loadsegment(es, v)
146
147#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
148#define set_user_seg(seg, v) loadsegment_##seg(v)
149
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800150#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800151 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152}
153
Hiroshi Shimamoto8801ead2009-02-20 19:00:13 -0800154#define GET_SEG(seg) ({ \
155 unsigned short tmp; \
156 get_user_ex(tmp, &sc->seg); \
157 tmp; \
158})
159
160#define COPY_SEG_CPL3(seg) do { \
161 regs->seg = GET_SEG(seg) | 3; \
162} while (0)
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800163
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800164#define RELOAD_SEG(seg) { \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800165 unsigned int pre = GET_SEG(seg); \
166 unsigned int cur = get_user_seg(seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800167 pre |= 3; \
168 if (pre != cur) \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800169 set_user_seg(seg, pre); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800170}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100172static int ia32_restore_sigcontext(struct pt_regs *regs,
173 struct sigcontext_ia32 __user *sc,
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800174 unsigned int *pax)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100175{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800176 unsigned int tmpflags, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700177 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100178 u32 tmp;
179
180 /* Always make any pending restarted system calls return -EINTR */
181 current_thread_info()->restart_block.fn = do_no_restart_syscall;
182
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800183 get_user_try {
184 /*
185 * Reload fs and gs if they have changed in the signal
186 * handler. This does not handle long fs/gs base changes in
187 * the handler, but does not clobber them at least in the
188 * normal case.
189 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800190 RELOAD_SEG(gs);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800191 RELOAD_SEG(fs);
192 RELOAD_SEG(ds);
193 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800195 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
196 COPY(dx); COPY(cx); COPY(ip);
197 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800199 COPY_SEG_CPL3(cs);
200 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800202 get_user_ex(tmpflags, &sc->flags);
203 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
204 /* disable syscall checks */
205 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100206
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800207 get_user_ex(tmp, &sc->fpstate);
208 buf = compat_ptr(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800210 get_user_ex(*pax, &sc->ax);
211 } get_user_catch(err);
212
H. Peter Anvin49b8c692012-09-21 17:18:44 -0700213 err |= restore_xstate_sig(buf, 1);
H. Peter Anvin5e883532012-09-21 12:43:15 -0700214
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216}
217
Al Viro3fe26fa2012-11-12 14:32:42 -0500218asmlinkage long sys32_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219{
Al Viro3fe26fa2012-11-12 14:32:42 -0500220 struct pt_regs *regs = current_pt_regs();
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800221 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100223 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
225 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
226 goto badframe;
227 if (__get_user(set.sig[0], &frame->sc.oldmask)
228 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100229 && __copy_from_user((((char *) &set.sig) + 4),
230 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 sizeof(frame->extramask))))
232 goto badframe;
233
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200234 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100235
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100236 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100238 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240badframe:
241 signal_fault(regs, frame, "32bit sigreturn");
242 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100243}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Al Viro3fe26fa2012-11-12 14:32:42 -0500245asmlinkage long sys32_rt_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246{
Al Viro3fe26fa2012-11-12 14:32:42 -0500247 struct pt_regs *regs = current_pt_regs();
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800248 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100250 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800252 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
254 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
255 goto badframe;
256 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
257 goto badframe;
258
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200259 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100260
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100261 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 goto badframe;
263
Al Viro90268432012-12-14 14:47:53 -0500264 if (compat_restore_altstack(&frame->uc.uc_stack))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 goto badframe;
266
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100267 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
269badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100270 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100272}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
274/*
275 * Set up a signal frame.
276 */
277
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100278static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700279 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100280 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800282 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800284 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800285 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
286 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
287 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
288 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800290 put_user_ex(regs->di, &sc->di);
291 put_user_ex(regs->si, &sc->si);
292 put_user_ex(regs->bp, &sc->bp);
293 put_user_ex(regs->sp, &sc->sp);
294 put_user_ex(regs->bx, &sc->bx);
295 put_user_ex(regs->dx, &sc->dx);
296 put_user_ex(regs->cx, &sc->cx);
297 put_user_ex(regs->ax, &sc->ax);
Srikar Dronamraju51e7dc72012-03-12 14:55:55 +0530298 put_user_ex(current->thread.trap_nr, &sc->trapno);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800299 put_user_ex(current->thread.error_code, &sc->err);
300 put_user_ex(regs->ip, &sc->ip);
301 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
302 put_user_ex(regs->flags, &sc->flags);
303 put_user_ex(regs->sp, &sc->sp_at_signal);
304 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800306 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800308 /* non-iBCS2 extensions.. */
309 put_user_ex(mask, &sc->oldmask);
310 put_user_ex(current->thread.cr2, &sc->cr2);
311 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 return err;
314}
315
316/*
317 * Determine which stack to use..
318 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100319static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700320 size_t frame_size,
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200321 void __user **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100323 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100326 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328 /* This is the X/Open sanctioned signal stack switching. */
329 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100330 if (sas_ss_flags(sp) == 0)
331 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 }
333
334 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800335 else if ((regs->ss & 0xffff) != __USER32_DS &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100337 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100338 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700340 if (used_math()) {
Suresh Siddha72a671c2012-07-24 16:05:29 -0700341 unsigned long fx_aligned, math_size;
342
343 sp = alloc_mathframe(sp, 1, &fx_aligned, &math_size);
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200344 *fpstate = (struct _fpstate_ia32 __user *) sp;
Suresh Siddha72a671c2012-07-24 16:05:29 -0700345 if (save_xstate_sig(*fpstate, (void __user *)fx_aligned,
346 math_size) < 0)
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800347 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700348 }
349
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100350 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200351 /* Align the stack pointer according to the i386 ABI,
352 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100353 sp = ((sp + 4) & -16ul) - 4;
354 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355}
356
Roland McGrath0928d6e2005-06-23 00:08:37 -0700357int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100358 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800360 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100361 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700363 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100365 /* copy_to_user optimizes that into a single 8 byte store */
366 static const struct {
367 u16 poplmovl;
368 u32 val;
369 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100370 } __attribute__((packed)) code = {
371 0xb858, /* popl %eax ; movl $...,%eax */
372 __NR_ia32_sigreturn,
373 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100374 };
375
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700376 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700379 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700381 if (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700382 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700384 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700385 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
387 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700388 if (__copy_to_user(frame->extramask, &set->sig[1],
389 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700390 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
Roland McGrathaf65d642008-01-30 13:30:43 +0100393 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100394 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100395 } else {
396 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700397 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100398 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
399 sigreturn);
400 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100401 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100402 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100403
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800404 put_user_try {
405 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
406
407 /*
408 * These are actually not used anymore, but left because some
409 * gdb versions depend on them as a marker.
410 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200411 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800412 } put_user_catch(err);
413
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700415 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
417 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100418 regs->sp = (unsigned long) frame;
419 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Andi Kleen536e3ee2006-09-26 10:52:41 +0200421 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100422 regs->ax = sig;
423 regs->dx = 0;
424 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200425
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700426 loadsegment(ds, __USER32_DS);
427 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100429 regs->cs = __USER32_CS;
430 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
Andi Kleen1d001df2006-09-26 10:52:26 +0200432 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433}
434
Roland McGrath0928d6e2005-06-23 00:08:37 -0700435int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100436 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800438 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100439 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700441 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100443 /* __copy_to_user optimizes that into a single 8 byte store */
444 static const struct {
445 u8 movl;
446 u32 val;
447 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800448 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100449 } __attribute__((packed)) code = {
450 0xb8,
451 __NR_ia32_rt_sigreturn,
452 0x80cd,
453 0,
454 };
455
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700456 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
458 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700459 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800461 put_user_try {
462 put_user_ex(sig, &frame->sig);
463 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
464 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800466 /* Create the ucontext. */
467 if (cpu_has_xsave)
468 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
469 else
470 put_user_ex(0, &frame->uc.uc_flags);
471 put_user_ex(0, &frame->uc.uc_link);
Al Viroc40702c2012-11-20 14:24:26 -0500472 err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800474 if (ka->sa.sa_flags & SA_RESTORER)
475 restorer = ka->sa.sa_restorer;
476 else
477 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
478 rt_sigreturn);
479 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800481 /*
482 * Not actually used anymore, but left because some gdb
483 * versions need it.
484 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200485 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800486 } put_user_catch(err);
487
H. Peter Anvin5e883532012-09-21 12:43:15 -0700488 err |= copy_siginfo_to_user32(&frame->info, info);
489 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
490 regs, set->sig[0]);
491 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
492
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700494 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
496 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100497 regs->sp = (unsigned long) frame;
498 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500500 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100501 regs->ax = sig;
502 regs->dx = (unsigned long) &frame->info;
503 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500504
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700505 loadsegment(ds, __USER32_DS);
506 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100507
508 regs->cs = __USER32_CS;
509 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Andi Kleen1d001df2006-09-26 10:52:26 +0200511 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512}