blob: f9e181aaba979190be8d3d18ebf437c2e3a22e69 [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
Al Viroce395962013-10-13 17:23:53 -040037int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -070038{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080039 int err = 0;
Suresh Siddha0b91f452012-06-14 18:07:15 -070040 bool ia32 = test_thread_flag(TIF_IA32);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010041
42 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 return -EFAULT;
44
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080045 put_user_try {
46 /* If you change siginfo_t structure, please make sure that
47 this code is fixed accordingly.
48 It should never copy any pad contained in the structure
49 to avoid security leaks, but must copy the generic
50 3 ints plus the relevant union member. */
51 put_user_ex(from->si_signo, &to->si_signo);
52 put_user_ex(from->si_errno, &to->si_errno);
53 put_user_ex((short)from->si_code, &to->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080055 if (from->si_code < 0) {
56 put_user_ex(from->si_pid, &to->si_pid);
57 put_user_ex(from->si_uid, &to->si_uid);
58 put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
59 } else {
60 /*
61 * First 32bits of unions are always present:
62 * si_pid === si_band === si_tid === si_addr(LS half)
63 */
64 put_user_ex(from->_sifields._pad[0],
65 &to->_sifields._pad[0]);
66 switch (from->si_code >> 16) {
67 case __SI_FAULT >> 16:
68 break;
Will Drewrya0727e82012-04-12 16:48:00 -050069 case __SI_SYS >> 16:
70 put_user_ex(from->si_syscall, &to->si_syscall);
71 put_user_ex(from->si_arch, &to->si_arch);
72 break;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080073 case __SI_CHLD >> 16:
H. Peter Anvine7084fd2012-03-05 13:40:24 -080074 if (ia32) {
75 put_user_ex(from->si_utime, &to->si_utime);
76 put_user_ex(from->si_stime, &to->si_stime);
77 } else {
78 put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
79 put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
80 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080081 put_user_ex(from->si_status, &to->si_status);
82 /* FALL THROUGH */
83 default:
84 case __SI_KILL >> 16:
85 put_user_ex(from->si_uid, &to->si_uid);
86 break;
87 case __SI_POLL >> 16:
88 put_user_ex(from->si_fd, &to->si_fd);
89 break;
90 case __SI_TIMER >> 16:
91 put_user_ex(from->si_overrun, &to->si_overrun);
92 put_user_ex(ptr_to_compat(from->si_ptr),
93 &to->si_ptr);
94 break;
95 /* This is not generated by the kernel as of now. */
96 case __SI_RT >> 16:
97 case __SI_MESGQ >> 16:
98 put_user_ex(from->si_uid, &to->si_uid);
99 put_user_ex(from->si_int, &to->si_int);
100 break;
101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800103 } put_user_catch(err);
104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 return err;
106}
107
108int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
109{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800110 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 u32 ptr32;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100112
113 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 return -EFAULT;
115
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800116 get_user_try {
117 get_user_ex(to->si_signo, &from->si_signo);
118 get_user_ex(to->si_errno, &from->si_errno);
119 get_user_ex(to->si_code, &from->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800121 get_user_ex(to->si_pid, &from->si_pid);
122 get_user_ex(to->si_uid, &from->si_uid);
123 get_user_ex(ptr32, &from->si_ptr);
124 to->si_ptr = compat_ptr(ptr32);
125 } get_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127 return err;
128}
129
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130/*
131 * Do a signal return; undo the signal stack.
132 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800133#define loadsegment_gs(v) load_gs_index(v)
134#define loadsegment_fs(v) loadsegment(fs, v)
135#define loadsegment_ds(v) loadsegment(ds, v)
136#define loadsegment_es(v) loadsegment(es, v)
137
138#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
139#define set_user_seg(seg, v) loadsegment_##seg(v)
140
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800141#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800142 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143}
144
Hiroshi Shimamoto8801ead2009-02-20 19:00:13 -0800145#define GET_SEG(seg) ({ \
146 unsigned short tmp; \
147 get_user_ex(tmp, &sc->seg); \
148 tmp; \
149})
150
151#define COPY_SEG_CPL3(seg) do { \
152 regs->seg = GET_SEG(seg) | 3; \
153} while (0)
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800154
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800155#define RELOAD_SEG(seg) { \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800156 unsigned int pre = GET_SEG(seg); \
157 unsigned int cur = get_user_seg(seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800158 pre |= 3; \
159 if (pre != cur) \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800160 set_user_seg(seg, pre); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800161}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100163static int ia32_restore_sigcontext(struct pt_regs *regs,
164 struct sigcontext_ia32 __user *sc,
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800165 unsigned int *pax)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100166{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800167 unsigned int tmpflags, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700168 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100169 u32 tmp;
170
171 /* Always make any pending restarted system calls return -EINTR */
172 current_thread_info()->restart_block.fn = do_no_restart_syscall;
173
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800174 get_user_try {
175 /*
176 * Reload fs and gs if they have changed in the signal
177 * handler. This does not handle long fs/gs base changes in
178 * the handler, but does not clobber them at least in the
179 * normal case.
180 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800181 RELOAD_SEG(gs);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800182 RELOAD_SEG(fs);
183 RELOAD_SEG(ds);
184 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800186 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
187 COPY(dx); COPY(cx); COPY(ip);
188 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800190 COPY_SEG_CPL3(cs);
191 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800193 get_user_ex(tmpflags, &sc->flags);
194 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
195 /* disable syscall checks */
196 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100197
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800198 get_user_ex(tmp, &sc->fpstate);
199 buf = compat_ptr(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800201 get_user_ex(*pax, &sc->ax);
202 } get_user_catch(err);
203
H. Peter Anvin49b8c692012-09-21 17:18:44 -0700204 err |= restore_xstate_sig(buf, 1);
H. Peter Anvin5e883532012-09-21 12:43:15 -0700205
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207}
208
Al Viro3fe26fa2012-11-12 14:32:42 -0500209asmlinkage long sys32_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210{
Al Viro3fe26fa2012-11-12 14:32:42 -0500211 struct pt_regs *regs = current_pt_regs();
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800212 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100214 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
217 goto badframe;
218 if (__get_user(set.sig[0], &frame->sc.oldmask)
219 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100220 && __copy_from_user((((char *) &set.sig) + 4),
221 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 sizeof(frame->extramask))))
223 goto badframe;
224
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200225 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100226
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100227 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100229 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231badframe:
232 signal_fault(regs, frame, "32bit sigreturn");
233 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100234}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
Al Viro3fe26fa2012-11-12 14:32:42 -0500236asmlinkage long sys32_rt_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
Al Viro3fe26fa2012-11-12 14:32:42 -0500238 struct pt_regs *regs = current_pt_regs();
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800239 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100241 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800243 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
245 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
246 goto badframe;
247 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
248 goto badframe;
249
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200250 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100251
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100252 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 goto badframe;
254
Al Viro90268432012-12-14 14:47:53 -0500255 if (compat_restore_altstack(&frame->uc.uc_stack))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 goto badframe;
257
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100258 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
260badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100261 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100263}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
265/*
266 * Set up a signal frame.
267 */
268
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100269static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700270 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100271 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800273 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800275 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800276 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
277 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
278 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
279 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800281 put_user_ex(regs->di, &sc->di);
282 put_user_ex(regs->si, &sc->si);
283 put_user_ex(regs->bp, &sc->bp);
284 put_user_ex(regs->sp, &sc->sp);
285 put_user_ex(regs->bx, &sc->bx);
286 put_user_ex(regs->dx, &sc->dx);
287 put_user_ex(regs->cx, &sc->cx);
288 put_user_ex(regs->ax, &sc->ax);
Srikar Dronamraju51e7dc72012-03-12 14:55:55 +0530289 put_user_ex(current->thread.trap_nr, &sc->trapno);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800290 put_user_ex(current->thread.error_code, &sc->err);
291 put_user_ex(regs->ip, &sc->ip);
292 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
293 put_user_ex(regs->flags, &sc->flags);
294 put_user_ex(regs->sp, &sc->sp_at_signal);
295 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800297 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800299 /* non-iBCS2 extensions.. */
300 put_user_ex(mask, &sc->oldmask);
301 put_user_ex(current->thread.cr2, &sc->cr2);
302 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304 return err;
305}
306
307/*
308 * Determine which stack to use..
309 */
Al Viro235b8022012-11-09 23:51:47 -0500310static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700311 size_t frame_size,
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200312 void __user **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100314 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100317 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319 /* This is the X/Open sanctioned signal stack switching. */
Al Viro235b8022012-11-09 23:51:47 -0500320 if (ksig->ka.sa.sa_flags & SA_ONSTACK)
321 sp = sigsp(sp, ksig);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800323 else if ((regs->ss & 0xffff) != __USER32_DS &&
Al Viro235b8022012-11-09 23:51:47 -0500324 !(ksig->ka.sa.sa_flags & SA_RESTORER) &&
325 ksig->ka.sa.sa_restorer)
326 sp = (unsigned long) ksig->ka.sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700328 if (used_math()) {
Suresh Siddha72a671c2012-07-24 16:05:29 -0700329 unsigned long fx_aligned, math_size;
330
331 sp = alloc_mathframe(sp, 1, &fx_aligned, &math_size);
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200332 *fpstate = (struct _fpstate_ia32 __user *) sp;
Suresh Siddha72a671c2012-07-24 16:05:29 -0700333 if (save_xstate_sig(*fpstate, (void __user *)fx_aligned,
334 math_size) < 0)
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800335 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700336 }
337
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100338 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200339 /* Align the stack pointer according to the i386 ABI,
340 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100341 sp = ((sp + 4) & -16ul) - 4;
342 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343}
344
Al Viro235b8022012-11-09 23:51:47 -0500345int ia32_setup_frame(int sig, struct ksignal *ksig,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100346 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800348 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100349 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700351 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100353 /* copy_to_user optimizes that into a single 8 byte store */
354 static const struct {
355 u16 poplmovl;
356 u32 val;
357 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100358 } __attribute__((packed)) code = {
359 0xb858, /* popl %eax ; movl $...,%eax */
360 __NR_ia32_sigreturn,
361 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100362 };
363
Al Viro235b8022012-11-09 23:51:47 -0500364 frame = get_sigframe(ksig, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700367 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700369 if (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700370 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700372 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700373 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700376 if (__copy_to_user(frame->extramask, &set->sig[1],
377 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700378 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Al Viro235b8022012-11-09 23:51:47 -0500381 if (ksig->ka.sa.sa_flags & SA_RESTORER) {
382 restorer = ksig->ka.sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100383 } else {
384 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700385 if (current->mm->context.vdso)
Andy Lutomirski6f121e52014-05-05 12:19:34 -0700386 restorer = current->mm->context.vdso +
387 selected_vdso32->sym___kernel_sigreturn;
Roland McGrathaf65d642008-01-30 13:30:43 +0100388 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100389 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100390 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100391
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800392 put_user_try {
393 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
394
395 /*
396 * These are actually not used anymore, but left because some
397 * gdb versions depend on them as a marker.
398 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200399 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800400 } put_user_catch(err);
401
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700403 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
405 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100406 regs->sp = (unsigned long) frame;
Al Viro235b8022012-11-09 23:51:47 -0500407 regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Andi Kleen536e3ee2006-09-26 10:52:41 +0200409 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100410 regs->ax = sig;
411 regs->dx = 0;
412 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200413
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700414 loadsegment(ds, __USER32_DS);
415 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100417 regs->cs = __USER32_CS;
418 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Andi Kleen1d001df2006-09-26 10:52:26 +0200420 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421}
422
Al Viro235b8022012-11-09 23:51:47 -0500423int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100424 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800426 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100427 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700429 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100431 /* __copy_to_user optimizes that into a single 8 byte store */
432 static const struct {
433 u8 movl;
434 u32 val;
435 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800436 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100437 } __attribute__((packed)) code = {
438 0xb8,
439 __NR_ia32_rt_sigreturn,
440 0x80cd,
441 0,
442 };
443
Al Viro235b8022012-11-09 23:51:47 -0500444 frame = get_sigframe(ksig, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
446 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700447 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800449 put_user_try {
450 put_user_ex(sig, &frame->sig);
451 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
452 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800454 /* Create the ucontext. */
455 if (cpu_has_xsave)
456 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
457 else
458 put_user_ex(0, &frame->uc.uc_flags);
459 put_user_ex(0, &frame->uc.uc_link);
Al Virobd1c149a2013-09-01 20:35:01 +0100460 compat_save_altstack_ex(&frame->uc.uc_stack, regs->sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Al Viro235b8022012-11-09 23:51:47 -0500462 if (ksig->ka.sa.sa_flags & SA_RESTORER)
463 restorer = ksig->ka.sa.sa_restorer;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800464 else
Andy Lutomirski6f121e52014-05-05 12:19:34 -0700465 restorer = current->mm->context.vdso +
466 selected_vdso32->sym___kernel_rt_sigreturn;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800467 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800469 /*
470 * Not actually used anymore, but left because some gdb
471 * versions need it.
472 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200473 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800474 } put_user_catch(err);
475
Al Viro235b8022012-11-09 23:51:47 -0500476 err |= copy_siginfo_to_user32(&frame->info, &ksig->info);
H. Peter Anvin5e883532012-09-21 12:43:15 -0700477 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
478 regs, set->sig[0]);
479 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
480
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700482 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100485 regs->sp = (unsigned long) frame;
Al Viro235b8022012-11-09 23:51:47 -0500486 regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500488 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100489 regs->ax = sig;
490 regs->dx = (unsigned long) &frame->info;
491 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500492
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700493 loadsegment(ds, __USER32_DS);
494 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100495
496 regs->cs = __USER32_CS;
497 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
Andi Kleen1d001df2006-09-26 10:52:26 +0200499 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500}