blob: d6d8f4ca5136ed6a4c72c637de7491b8f62824d0 [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>
Ingo Molnar78f7f1e2015-04-24 02:54:44 +020024#include <asm/fpu/internal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <asm/ptrace.h>
26#include <asm/ia32_unistd.h>
27#include <asm/user32.h>
28#include <asm/sigcontext32.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <asm/proto.h>
Roland McGrathaf65d642008-01-30 13:30:43 +010030#include <asm/vdso.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080031#include <asm/sigframe.h>
H. Peter Anvinf28f0c22012-02-19 07:38:43 -080032#include <asm/sighandling.h>
Jaswinder Singh Rajput2f06de02008-12-27 21:37:10 +053033#include <asm/sys_ia32.h>
H. Peter Anvin49b8c692012-09-21 17:18:44 -070034#include <asm/smap.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080035
Al Viroce395962013-10-13 17:23:53 -040036int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -070037{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080038 int err = 0;
Suresh Siddha0b91f452012-06-14 18:07:15 -070039 bool ia32 = test_thread_flag(TIF_IA32);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010040
41 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 return -EFAULT;
43
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080044 put_user_try {
45 /* If you change siginfo_t structure, please make sure that
46 this code is fixed accordingly.
47 It should never copy any pad contained in the structure
48 to avoid security leaks, but must copy the generic
49 3 ints plus the relevant union member. */
50 put_user_ex(from->si_signo, &to->si_signo);
51 put_user_ex(from->si_errno, &to->si_errno);
52 put_user_ex((short)from->si_code, &to->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080054 if (from->si_code < 0) {
55 put_user_ex(from->si_pid, &to->si_pid);
56 put_user_ex(from->si_uid, &to->si_uid);
57 put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
58 } else {
59 /*
60 * First 32bits of unions are always present:
61 * si_pid === si_band === si_tid === si_addr(LS half)
62 */
63 put_user_ex(from->_sifields._pad[0],
64 &to->_sifields._pad[0]);
65 switch (from->si_code >> 16) {
66 case __SI_FAULT >> 16:
67 break;
Will Drewrya0727e82012-04-12 16:48:00 -050068 case __SI_SYS >> 16:
69 put_user_ex(from->si_syscall, &to->si_syscall);
70 put_user_ex(from->si_arch, &to->si_arch);
71 break;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080072 case __SI_CHLD >> 16:
H. Peter Anvine7084fd2012-03-05 13:40:24 -080073 if (ia32) {
74 put_user_ex(from->si_utime, &to->si_utime);
75 put_user_ex(from->si_stime, &to->si_stime);
76 } else {
77 put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
78 put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
79 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080080 put_user_ex(from->si_status, &to->si_status);
81 /* FALL THROUGH */
82 default:
83 case __SI_KILL >> 16:
84 put_user_ex(from->si_uid, &to->si_uid);
85 break;
86 case __SI_POLL >> 16:
87 put_user_ex(from->si_fd, &to->si_fd);
88 break;
89 case __SI_TIMER >> 16:
90 put_user_ex(from->si_overrun, &to->si_overrun);
91 put_user_ex(ptr_to_compat(from->si_ptr),
92 &to->si_ptr);
93 break;
94 /* This is not generated by the kernel as of now. */
95 case __SI_RT >> 16:
96 case __SI_MESGQ >> 16:
97 put_user_ex(from->si_uid, &to->si_uid);
98 put_user_ex(from->si_int, &to->si_int);
99 break;
100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800102 } put_user_catch(err);
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 return err;
105}
106
107int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
108{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800109 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 u32 ptr32;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100111
112 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 return -EFAULT;
114
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800115 get_user_try {
116 get_user_ex(to->si_signo, &from->si_signo);
117 get_user_ex(to->si_errno, &from->si_errno);
118 get_user_ex(to->si_code, &from->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800120 get_user_ex(to->si_pid, &from->si_pid);
121 get_user_ex(to->si_uid, &from->si_uid);
122 get_user_ex(ptr32, &from->si_ptr);
123 to->si_ptr = compat_ptr(ptr32);
124 } get_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126 return err;
127}
128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129/*
130 * Do a signal return; undo the signal stack.
131 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800132#define loadsegment_gs(v) load_gs_index(v)
133#define loadsegment_fs(v) loadsegment(fs, v)
134#define loadsegment_ds(v) loadsegment(ds, v)
135#define loadsegment_es(v) loadsegment(es, v)
136
137#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
138#define set_user_seg(seg, v) loadsegment_##seg(v)
139
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800140#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800141 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142}
143
Hiroshi Shimamoto8801ead42009-02-20 19:00:13 -0800144#define GET_SEG(seg) ({ \
145 unsigned short tmp; \
146 get_user_ex(tmp, &sc->seg); \
147 tmp; \
148})
149
150#define COPY_SEG_CPL3(seg) do { \
151 regs->seg = GET_SEG(seg) | 3; \
152} while (0)
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800153
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800154#define RELOAD_SEG(seg) { \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800155 unsigned int pre = GET_SEG(seg); \
156 unsigned int cur = get_user_seg(seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800157 pre |= 3; \
158 if (pre != cur) \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800159 set_user_seg(seg, pre); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800160}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100162static int ia32_restore_sigcontext(struct pt_regs *regs,
Brian Gerst6a3713f2015-04-04 08:58:23 -0400163 struct sigcontext_ia32 __user *sc)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100164{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800165 unsigned int tmpflags, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700166 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100167 u32 tmp;
168
169 /* Always make any pending restarted system calls return -EINTR */
Andy Lutomirskif56141e2015-02-12 15:01:14 -0800170 current->restart_block.fn = do_no_restart_syscall;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100171
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800172 get_user_try {
173 /*
174 * Reload fs and gs if they have changed in the signal
175 * handler. This does not handle long fs/gs base changes in
176 * the handler, but does not clobber them at least in the
177 * normal case.
178 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800179 RELOAD_SEG(gs);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800180 RELOAD_SEG(fs);
181 RELOAD_SEG(ds);
182 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800184 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
Brian Gerst6a3713f2015-04-04 08:58:23 -0400185 COPY(dx); COPY(cx); COPY(ip); COPY(ax);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800186 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800188 COPY_SEG_CPL3(cs);
189 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800191 get_user_ex(tmpflags, &sc->flags);
192 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
193 /* disable syscall checks */
194 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100195
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800196 get_user_ex(tmp, &sc->fpstate);
197 buf = compat_ptr(tmp);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800198 } get_user_catch(err);
199
H. Peter Anvin49b8c692012-09-21 17:18:44 -0700200 err |= restore_xstate_sig(buf, 1);
H. Peter Anvin5e883532012-09-21 12:43:15 -0700201
Brian Gerst1daeaa32015-03-21 18:54:21 -0400202 force_iret();
203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205}
206
Al Viro3fe26fa2012-11-12 14:32:42 -0500207asmlinkage long sys32_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
Al Viro3fe26fa2012-11-12 14:32:42 -0500209 struct pt_regs *regs = current_pt_regs();
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800210 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 sigset_t set;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
214 goto badframe;
215 if (__get_user(set.sig[0], &frame->sc.oldmask)
216 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100217 && __copy_from_user((((char *) &set.sig) + 4),
218 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 sizeof(frame->extramask))))
220 goto badframe;
221
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200222 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100223
Brian Gerst6a3713f2015-04-04 08:58:23 -0400224 if (ia32_restore_sigcontext(regs, &frame->sc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 goto badframe;
Brian Gerst6a3713f2015-04-04 08:58:23 -0400226 return regs->ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
228badframe:
229 signal_fault(regs, frame, "32bit sigreturn");
230 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100231}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
Al Viro3fe26fa2012-11-12 14:32:42 -0500233asmlinkage long sys32_rt_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234{
Al Viro3fe26fa2012-11-12 14:32:42 -0500235 struct pt_regs *regs = current_pt_regs();
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800236 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 sigset_t set;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800239 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
241 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
242 goto badframe;
243 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
244 goto badframe;
245
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200246 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100247
Brian Gerst6a3713f2015-04-04 08:58:23 -0400248 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 goto badframe;
250
Al Viro90268432012-12-14 14:47:53 -0500251 if (compat_restore_altstack(&frame->uc.uc_stack))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 goto badframe;
253
Brian Gerst6a3713f2015-04-04 08:58:23 -0400254 return regs->ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
256badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100257 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100259}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
261/*
262 * Set up a signal frame.
263 */
264
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100265static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700266 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100267 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800269 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800271 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800272 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
273 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
274 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
275 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800277 put_user_ex(regs->di, &sc->di);
278 put_user_ex(regs->si, &sc->si);
279 put_user_ex(regs->bp, &sc->bp);
280 put_user_ex(regs->sp, &sc->sp);
281 put_user_ex(regs->bx, &sc->bx);
282 put_user_ex(regs->dx, &sc->dx);
283 put_user_ex(regs->cx, &sc->cx);
284 put_user_ex(regs->ax, &sc->ax);
Srikar Dronamraju51e7dc72012-03-12 14:55:55 +0530285 put_user_ex(current->thread.trap_nr, &sc->trapno);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800286 put_user_ex(current->thread.error_code, &sc->err);
287 put_user_ex(regs->ip, &sc->ip);
288 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
289 put_user_ex(regs->flags, &sc->flags);
290 put_user_ex(regs->sp, &sc->sp_at_signal);
291 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800293 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800295 /* non-iBCS2 extensions.. */
296 put_user_ex(mask, &sc->oldmask);
297 put_user_ex(current->thread.cr2, &sc->cr2);
298 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
300 return err;
301}
302
303/*
304 * Determine which stack to use..
305 */
Al Viro235b8022012-11-09 23:51:47 -0500306static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700307 size_t frame_size,
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200308 void __user **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309{
Ingo Molnarc5bedc62015-04-23 12:49:20 +0200310 struct fpu *fpu = &current->thread.fpu;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100311 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100314 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316 /* This is the X/Open sanctioned signal stack switching. */
Al Viro235b8022012-11-09 23:51:47 -0500317 if (ksig->ka.sa.sa_flags & SA_ONSTACK)
318 sp = sigsp(sp, ksig);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800320 else if ((regs->ss & 0xffff) != __USER32_DS &&
Al Viro235b8022012-11-09 23:51:47 -0500321 !(ksig->ka.sa.sa_flags & SA_RESTORER) &&
322 ksig->ka.sa.sa_restorer)
323 sp = (unsigned long) ksig->ka.sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
Ingo Molnarc5bedc62015-04-23 12:49:20 +0200325 if (fpu->fpstate_active) {
Suresh Siddha72a671c2012-07-24 16:05:29 -0700326 unsigned long fx_aligned, math_size;
327
328 sp = alloc_mathframe(sp, 1, &fx_aligned, &math_size);
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200329 *fpstate = (struct _fpstate_ia32 __user *) sp;
Suresh Siddha72a671c2012-07-24 16:05:29 -0700330 if (save_xstate_sig(*fpstate, (void __user *)fx_aligned,
331 math_size) < 0)
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800332 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700333 }
334
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100335 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200336 /* Align the stack pointer according to the i386 ABI,
337 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100338 sp = ((sp + 4) & -16ul) - 4;
339 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340}
341
Al Viro235b8022012-11-09 23:51:47 -0500342int ia32_setup_frame(int sig, struct ksignal *ksig,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100343 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800345 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100346 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700348 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100350 /* copy_to_user optimizes that into a single 8 byte store */
351 static const struct {
352 u16 poplmovl;
353 u32 val;
354 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100355 } __attribute__((packed)) code = {
356 0xb858, /* popl %eax ; movl $...,%eax */
357 __NR_ia32_sigreturn,
358 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100359 };
360
Al Viro235b8022012-11-09 23:51:47 -0500361 frame = get_sigframe(ksig, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
363 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700364 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700366 if (__put_user(sig, &frame->sig))
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 (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700370 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
372 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700373 if (__copy_to_user(frame->extramask, &set->sig[1],
374 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700375 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Al Viro235b8022012-11-09 23:51:47 -0500378 if (ksig->ka.sa.sa_flags & SA_RESTORER) {
379 restorer = ksig->ka.sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100380 } else {
381 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700382 if (current->mm->context.vdso)
Andy Lutomirski6f121e52014-05-05 12:19:34 -0700383 restorer = current->mm->context.vdso +
384 selected_vdso32->sym___kernel_sigreturn;
Roland McGrathaf65d642008-01-30 13:30:43 +0100385 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100386 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100387 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100388
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800389 put_user_try {
390 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
391
392 /*
393 * These are actually not used anymore, but left because some
394 * gdb versions depend on them as a marker.
395 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200396 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800397 } put_user_catch(err);
398
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700400 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
402 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100403 regs->sp = (unsigned long) frame;
Al Viro235b8022012-11-09 23:51:47 -0500404 regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Andi Kleen536e3ee2006-09-26 10:52:41 +0200406 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100407 regs->ax = sig;
408 regs->dx = 0;
409 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200410
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700411 loadsegment(ds, __USER32_DS);
412 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100414 regs->cs = __USER32_CS;
415 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Andi Kleen1d001df2006-09-26 10:52:26 +0200417 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418}
419
Al Viro235b8022012-11-09 23:51:47 -0500420int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100421 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800423 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100424 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700426 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100428 /* __copy_to_user optimizes that into a single 8 byte store */
429 static const struct {
430 u8 movl;
431 u32 val;
432 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800433 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100434 } __attribute__((packed)) code = {
435 0xb8,
436 __NR_ia32_rt_sigreturn,
437 0x80cd,
438 0,
439 };
440
Al Viro235b8022012-11-09 23:51:47 -0500441 frame = get_sigframe(ksig, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
443 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700444 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800446 put_user_try {
447 put_user_ex(sig, &frame->sig);
448 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
449 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800451 /* Create the ucontext. */
452 if (cpu_has_xsave)
453 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
454 else
455 put_user_ex(0, &frame->uc.uc_flags);
456 put_user_ex(0, &frame->uc.uc_link);
Al Virobd1c149a2013-09-01 20:35:01 +0100457 compat_save_altstack_ex(&frame->uc.uc_stack, regs->sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Al Viro235b8022012-11-09 23:51:47 -0500459 if (ksig->ka.sa.sa_flags & SA_RESTORER)
460 restorer = ksig->ka.sa.sa_restorer;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800461 else
Andy Lutomirski6f121e52014-05-05 12:19:34 -0700462 restorer = current->mm->context.vdso +
463 selected_vdso32->sym___kernel_rt_sigreturn;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800464 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800466 /*
467 * Not actually used anymore, but left because some gdb
468 * versions need it.
469 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200470 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800471 } put_user_catch(err);
472
Al Viro235b8022012-11-09 23:51:47 -0500473 err |= copy_siginfo_to_user32(&frame->info, &ksig->info);
H. Peter Anvin5e883532012-09-21 12:43:15 -0700474 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
475 regs, set->sig[0]);
476 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700479 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
481 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100482 regs->sp = (unsigned long) frame;
Al Viro235b8022012-11-09 23:51:47 -0500483 regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500485 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100486 regs->ax = sig;
487 regs->dx = (unsigned long) &frame->info;
488 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500489
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700490 loadsegment(ds, __USER32_DS);
491 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100492
493 regs->cs = __USER32_CS;
494 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
Andi Kleen1d001df2006-09-26 10:52:26 +0200496 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497}