Blame view
arch/x86/kernel/signal.c
20.9 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
1da177e4c Linux-2.6.12-rc2 |
2 |
* Copyright (C) 1991, 1992 Linus Torvalds |
e5fa2d063 x86: signal: unif... |
3 |
* Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs |
1da177e4c Linux-2.6.12-rc2 |
4 5 6 |
* * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes |
e5fa2d063 x86: signal: unif... |
7 |
* 2000-2002 x86-64 support by Andi Kleen |
1da177e4c Linux-2.6.12-rc2 |
8 |
*/ |
5c9b3a0c7 x86: signal: cosm... |
9 10 11 |
#include <linux/sched.h> #include <linux/mm.h> #include <linux/smp.h> |
1da177e4c Linux-2.6.12-rc2 |
12 13 14 15 |
#include <linux/kernel.h> #include <linux/signal.h> #include <linux/errno.h> #include <linux/wait.h> |
5c9b3a0c7 x86: signal: cosm... |
16 |
#include <linux/ptrace.h> |
36a033082 x86: tracehook_si... |
17 |
#include <linux/tracehook.h> |
5c9b3a0c7 x86: signal: cosm... |
18 19 20 21 |
#include <linux/unistd.h> #include <linux/stddef.h> #include <linux/personality.h> #include <linux/uaccess.h> |
7c68af6e3 core, x86: Add us... |
22 |
#include <linux/user-return-notifier.h> |
7e907f489 x86: clean up arc... |
23 |
|
1da177e4c Linux-2.6.12-rc2 |
24 25 |
#include <asm/processor.h> #include <asm/ucontext.h> |
1da177e4c Linux-2.6.12-rc2 |
26 |
#include <asm/i387.h> |
6c3652efc x86 vDSO: i386 vd... |
27 |
#include <asm/vdso.h> |
4efc0670b x86, mce: use 64b... |
28 |
#include <asm/mce.h> |
5c9b3a0c7 x86: signal: cosm... |
29 30 31 32 |
#ifdef CONFIG_X86_64 #include <asm/proto.h> #include <asm/ia32_unistd.h> |
5c9b3a0c7 x86: signal: cosm... |
33 |
#endif /* CONFIG_X86_64 */ |
bb57925f5 x86_32: signal: u... |
34 |
#include <asm/syscall.h> |
bbc1f698a x86: Introducing ... |
35 |
#include <asm/syscalls.h> |
7e907f489 x86: clean up arc... |
36 |
|
41af86fad x86: signal: move... |
37 |
#include <asm/sigframe.h> |
1da177e4c Linux-2.6.12-rc2 |
38 |
|
1da177e4c Linux-2.6.12-rc2 |
39 |
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
1a1768039 x86: Use FIX_EFLA... |
40 41 42 43 44 45 46 47 48 49 |
#define __FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \ X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \ X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \ X86_EFLAGS_CF) #ifdef CONFIG_X86_32 # define FIX_EFLAGS (__FIX_EFLAGS | X86_EFLAGS_RF) #else # define FIX_EFLAGS __FIX_EFLAGS #endif |
d9a89a26e x86: add %gs acce... |
50 51 52 |
#define COPY(x) do { \ get_user_ex(regs->x, &sc->x); \ } while (0) |
2601657d2 x86: signal: move... |
53 |
|
d9a89a26e x86: add %gs acce... |
54 55 56 57 58 |
#define GET_SEG(seg) ({ \ unsigned short tmp; \ get_user_ex(tmp, &sc->seg); \ tmp; \ }) |
2601657d2 x86: signal: move... |
59 |
|
d9a89a26e x86: add %gs acce... |
60 61 62 |
#define COPY_SEG(seg) do { \ regs->seg = GET_SEG(seg); \ } while (0) |
2601657d2 x86: signal: move... |
63 |
|
d9a89a26e x86: add %gs acce... |
64 65 66 |
#define COPY_SEG_CPL3(seg) do { \ regs->seg = GET_SEG(seg) | 3; \ } while (0) |
2601657d2 x86: signal: move... |
67 68 69 70 71 72 73 74 75 76 77 |
static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned long *pax) { void __user *buf; unsigned int tmpflags; unsigned int err = 0; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; |
98e3d45ed x86: signal: use ... |
78 |
get_user_try { |
2601657d2 x86: signal: move... |
79 |
#ifdef CONFIG_X86_32 |
d9a89a26e x86: add %gs acce... |
80 |
set_user_gs(regs, GET_SEG(gs)); |
98e3d45ed x86: signal: use ... |
81 82 83 |
COPY_SEG(fs); COPY_SEG(es); COPY_SEG(ds); |
2601657d2 x86: signal: move... |
84 |
#endif /* CONFIG_X86_32 */ |
98e3d45ed x86: signal: use ... |
85 86 |
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); COPY(dx); COPY(cx); COPY(ip); |
2601657d2 x86: signal: move... |
87 88 |
#ifdef CONFIG_X86_64 |
98e3d45ed x86: signal: use ... |
89 90 91 92 93 94 95 96 |
COPY(r8); COPY(r9); COPY(r10); COPY(r11); COPY(r12); COPY(r13); COPY(r14); COPY(r15); |
2601657d2 x86: signal: move... |
97 98 99 |
#endif /* CONFIG_X86_64 */ #ifdef CONFIG_X86_32 |
98e3d45ed x86: signal: use ... |
100 101 |
COPY_SEG_CPL3(cs); COPY_SEG_CPL3(ss); |
2601657d2 x86: signal: move... |
102 |
#else /* !CONFIG_X86_32 */ |
98e3d45ed x86: signal: use ... |
103 104 105 106 |
/* Kernel saves and restores only the CS segment register on signals, * which is the bare minimum needed to allow mixed 32/64-bit code. * App's signal handler can save/restore other segments if needed. */ COPY_SEG_CPL3(cs); |
2601657d2 x86: signal: move... |
107 |
#endif /* CONFIG_X86_32 */ |
98e3d45ed x86: signal: use ... |
108 109 110 111 112 113 |
get_user_ex(tmpflags, &sc->flags); regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); regs->orig_ax = -1; /* disable syscall checks */ get_user_ex(buf, &sc->fpstate); err |= restore_i387_xstate(buf); |
2601657d2 x86: signal: move... |
114 |
|
98e3d45ed x86: signal: use ... |
115 116 |
get_user_ex(*pax, &sc->ax); } get_user_catch(err); |
2601657d2 x86: signal: move... |
117 |
|
2601657d2 x86: signal: move... |
118 119 120 121 122 123 124 125 |
return err; } static int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, struct pt_regs *regs, unsigned long mask) { int err = 0; |
98e3d45ed x86: signal: use ... |
126 |
put_user_try { |
2601657d2 x86: signal: move... |
127 |
|
98e3d45ed x86: signal: use ... |
128 |
#ifdef CONFIG_X86_32 |
d9a89a26e x86: add %gs acce... |
129 |
put_user_ex(get_user_gs(regs), (unsigned int __user *)&sc->gs); |
98e3d45ed x86: signal: use ... |
130 131 132 |
put_user_ex(regs->fs, (unsigned int __user *)&sc->fs); put_user_ex(regs->es, (unsigned int __user *)&sc->es); put_user_ex(regs->ds, (unsigned int __user *)&sc->ds); |
2601657d2 x86: signal: move... |
133 |
#endif /* CONFIG_X86_32 */ |
98e3d45ed x86: signal: use ... |
134 135 136 137 138 139 140 141 |
put_user_ex(regs->di, &sc->di); put_user_ex(regs->si, &sc->si); put_user_ex(regs->bp, &sc->bp); put_user_ex(regs->sp, &sc->sp); put_user_ex(regs->bx, &sc->bx); put_user_ex(regs->dx, &sc->dx); put_user_ex(regs->cx, &sc->cx); put_user_ex(regs->ax, &sc->ax); |
2601657d2 x86: signal: move... |
142 |
#ifdef CONFIG_X86_64 |
98e3d45ed x86: signal: use ... |
143 144 145 146 147 148 149 150 |
put_user_ex(regs->r8, &sc->r8); put_user_ex(regs->r9, &sc->r9); put_user_ex(regs->r10, &sc->r10); put_user_ex(regs->r11, &sc->r11); put_user_ex(regs->r12, &sc->r12); put_user_ex(regs->r13, &sc->r13); put_user_ex(regs->r14, &sc->r14); put_user_ex(regs->r15, &sc->r15); |
2601657d2 x86: signal: move... |
151 |
#endif /* CONFIG_X86_64 */ |
98e3d45ed x86: signal: use ... |
152 153 154 |
put_user_ex(current->thread.trap_no, &sc->trapno); put_user_ex(current->thread.error_code, &sc->err); put_user_ex(regs->ip, &sc->ip); |
2601657d2 x86: signal: move... |
155 |
#ifdef CONFIG_X86_32 |
98e3d45ed x86: signal: use ... |
156 157 158 159 |
put_user_ex(regs->cs, (unsigned int __user *)&sc->cs); put_user_ex(regs->flags, &sc->flags); put_user_ex(regs->sp, &sc->sp_at_signal); put_user_ex(regs->ss, (unsigned int __user *)&sc->ss); |
2601657d2 x86: signal: move... |
160 |
#else /* !CONFIG_X86_32 */ |
98e3d45ed x86: signal: use ... |
161 162 163 164 |
put_user_ex(regs->flags, &sc->flags); put_user_ex(regs->cs, &sc->cs); put_user_ex(0, &sc->gs); put_user_ex(0, &sc->fs); |
2601657d2 x86: signal: move... |
165 |
#endif /* CONFIG_X86_32 */ |
98e3d45ed x86: signal: use ... |
166 |
put_user_ex(fpstate, &sc->fpstate); |
2601657d2 x86: signal: move... |
167 |
|
98e3d45ed x86: signal: use ... |
168 169 170 171 |
/* non-iBCS2 extensions.. */ put_user_ex(mask, &sc->oldmask); put_user_ex(current->thread.cr2, &sc->cr2); } put_user_catch(err); |
2601657d2 x86: signal: move... |
172 173 174 |
return err; } |
1da177e4c Linux-2.6.12-rc2 |
175 |
/* |
bfeb91a94 x86: signal: cosm... |
176 |
* Set up a signal frame. |
1da177e4c Linux-2.6.12-rc2 |
177 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
178 179 180 181 |
/* * Determine which stack to use.. */ |
1fae0279c x86: signal: intr... |
182 183 184 185 186 187 188 189 190 191 192 193 194 |
static unsigned long align_sigframe(unsigned long sp) { #ifdef CONFIG_X86_32 /* * Align the stack pointer according to the i386 ABI, * i.e. so that on function entry ((sp + 4) & 15) == 0. */ sp = ((sp + 4) & -16ul) - 4; #else /* !CONFIG_X86_32 */ sp = round_down(sp, 16) - 8; #endif return sp; } |
1da177e4c Linux-2.6.12-rc2 |
195 |
static inline void __user * |
3c1c7f101 x86, xsave: dynam... |
196 |
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, |
144b0712d x86: signal: add ... |
197 |
void __user **fpstate) |
1da177e4c Linux-2.6.12-rc2 |
198 |
{ |
1da177e4c Linux-2.6.12-rc2 |
199 |
/* Default to using normal stack */ |
75779f052 x86: signal: unif... |
200 |
unsigned long sp = regs->sp; |
14fc9fbc7 x86: signal: chec... |
201 |
int onsigstack = on_sig_stack(sp); |
75779f052 x86: signal: unif... |
202 203 204 205 206 |
#ifdef CONFIG_X86_64 /* redzone */ sp -= 128; #endif /* CONFIG_X86_64 */ |
1da177e4c Linux-2.6.12-rc2 |
207 |
|
14fc9fbc7 x86: signal: chec... |
208 209 210 |
if (!onsigstack) { /* This is the X/Open sanctioned signal stack switching. */ if (ka->sa.sa_flags & SA_ONSTACK) { |
0f8f30892 x86: signal: chec... |
211 |
if (current->sas_ss_size) |
14fc9fbc7 x86: signal: chec... |
212 213 |
sp = current->sas_ss_sp + current->sas_ss_size; } else { |
75779f052 x86: signal: unif... |
214 |
#ifdef CONFIG_X86_32 |
14fc9fbc7 x86: signal: chec... |
215 216 217 218 219 |
/* This is the legacy signal stack switching. */ if ((regs->ss & 0xffff) != __USER_DS && !(ka->sa.sa_flags & SA_RESTORER) && ka->sa.sa_restorer) sp = (unsigned long) ka->sa.sa_restorer; |
75779f052 x86: signal: unif... |
220 |
#endif /* CONFIG_X86_32 */ |
14fc9fbc7 x86: signal: chec... |
221 |
} |
1da177e4c Linux-2.6.12-rc2 |
222 |
} |
3c1c7f101 x86, xsave: dynam... |
223 |
if (used_math()) { |
75779f052 x86: signal: unif... |
224 |
sp -= sig_xstate_size; |
250517021 x86, signals: fix... |
225 226 227 228 |
#ifdef CONFIG_X86_64 sp = round_down(sp, 64); #endif /* CONFIG_X86_64 */ *fpstate = (void __user *)sp; |
3c1c7f101 x86, xsave: dynam... |
229 |
} |
14fc9fbc7 x86: signal: chec... |
230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
sp = align_sigframe(sp - frame_size); /* * If we are on the alternate signal stack and would overflow it, don't. * Return an always-bogus address instead so we will die with SIGSEGV. */ if (onsigstack && !likely(on_sig_stack(sp))) return (void __user *)-1L; /* save i387 state */ if (used_math() && save_i387_xstate(*fpstate) < 0) return (void __user *)-1L; return (void __user *)sp; |
1da177e4c Linux-2.6.12-rc2 |
244 |
} |
75779f052 x86: signal: unif... |
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
#ifdef CONFIG_X86_32 static const struct { u16 poplmovl; u32 val; u16 int80; } __attribute__((packed)) retcode = { 0xb858, /* popl %eax; movl $..., %eax */ __NR_sigreturn, 0x80cd, /* int $0x80 */ }; static const struct { u8 movl; u32 val; u16 int80; u8 pad; } __attribute__((packed)) rt_retcode = { 0xb8, /* movl $..., %eax */ __NR_rt_sigreturn, 0x80cd, /* int $0x80 */ 0 }; |
7e907f489 x86: clean up arc... |
267 |
static int |
1d13024e6 x86: signal: spli... |
268 269 |
__setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) |
1da177e4c Linux-2.6.12-rc2 |
270 |
{ |
1da177e4c Linux-2.6.12-rc2 |
271 |
struct sigframe __user *frame; |
7e907f489 x86: clean up arc... |
272 |
void __user *restorer; |
1da177e4c Linux-2.6.12-rc2 |
273 |
int err = 0; |
ab5137015 x86, xsave: reorg... |
274 |
void __user *fpstate = NULL; |
1da177e4c Linux-2.6.12-rc2 |
275 |
|
3c1c7f101 x86, xsave: dynam... |
276 |
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
1da177e4c Linux-2.6.12-rc2 |
277 278 |
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
3d0aedd95 x86: signal: put ... |
279 |
return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
280 |
|
2ba48e16e x86: signal: remo... |
281 |
if (__put_user(sig, &frame->sig)) |
3d0aedd95 x86: signal: put ... |
282 |
return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
283 |
|
2ba48e16e x86: signal: remo... |
284 |
if (setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0])) |
3d0aedd95 x86: signal: put ... |
285 |
return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
286 287 |
if (_NSIG_WORDS > 1) { |
2ba48e16e x86: signal: remo... |
288 289 |
if (__copy_to_user(&frame->extramask, &set->sig[1], sizeof(frame->extramask))) |
3d0aedd95 x86: signal: put ... |
290 |
return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
291 |
} |
1a3e4ca41 x86 vDSO: don't u... |
292 |
if (current->mm->context.vdso) |
6c3652efc x86 vDSO: i386 vd... |
293 |
restorer = VDSO32_SYMBOL(current->mm->context.vdso, sigreturn); |
9fbbd4dd1 [PATCH] x86: Don'... |
294 |
else |
ade1af771 x86: remove unned... |
295 |
restorer = &frame->retcode; |
1da177e4c Linux-2.6.12-rc2 |
296 297 298 299 300 |
if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; /* Set up to return from userspace. */ err |= __put_user(restorer, &frame->pretcode); |
7e907f489 x86: clean up arc... |
301 |
|
1da177e4c Linux-2.6.12-rc2 |
302 |
/* |
7e907f489 x86: clean up arc... |
303 |
* This is popl %eax ; movl $__NR_sigreturn, %eax ; int $0x80 |
1da177e4c Linux-2.6.12-rc2 |
304 305 306 307 308 |
* * WE DO NOT USE IT ANY MORE! It's only left here for historical * reasons and because gdb uses it as a signature to notice * signal handler stack frames. */ |
4a6120485 x86: signal_32: i... |
309 |
err |= __put_user(*((u64 *)&retcode), (u64 *)frame->retcode); |
1da177e4c Linux-2.6.12-rc2 |
310 311 |
if (err) |
3d0aedd95 x86: signal: put ... |
312 |
return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
313 314 |
/* Set up registers for signal handler */ |
7e907f489 x86: clean up arc... |
315 316 317 |
regs->sp = (unsigned long)frame; regs->ip = (unsigned long)ka->sa.sa_handler; regs->ax = (unsigned long)sig; |
92bc20568 x86: change most ... |
318 319 |
regs->dx = 0; regs->cx = 0; |
1da177e4c Linux-2.6.12-rc2 |
320 |
|
65ea5b034 x86: rename the s... |
321 322 323 324 |
regs->ds = __USER_DS; regs->es = __USER_DS; regs->ss = __USER_DS; regs->cs = __USER_CS; |
1da177e4c Linux-2.6.12-rc2 |
325 |
|
283828f3c [PATCH] Handle TI... |
326 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
327 |
} |
1d13024e6 x86: signal: spli... |
328 329 |
static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) |
1da177e4c Linux-2.6.12-rc2 |
330 |
{ |
1da177e4c Linux-2.6.12-rc2 |
331 |
struct rt_sigframe __user *frame; |
7e907f489 x86: clean up arc... |
332 |
void __user *restorer; |
1da177e4c Linux-2.6.12-rc2 |
333 |
int err = 0; |
ab5137015 x86, xsave: reorg... |
334 |
void __user *fpstate = NULL; |
1da177e4c Linux-2.6.12-rc2 |
335 |
|
3c1c7f101 x86, xsave: dynam... |
336 |
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
1da177e4c Linux-2.6.12-rc2 |
337 338 |
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
3d0aedd95 x86: signal: put ... |
339 |
return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
340 |
|
98e3d45ed x86: signal: use ... |
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
put_user_try { put_user_ex(sig, &frame->sig); put_user_ex(&frame->info, &frame->pinfo); put_user_ex(&frame->uc, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ if (cpu_has_xsave) put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); else put_user_ex(0, &frame->uc.uc_flags); put_user_ex(0, &frame->uc.uc_link); put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); put_user_ex(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags); put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Set up to return from userspace. */ restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; put_user_ex(restorer, &frame->pretcode); /* * This is movl $__NR_rt_sigreturn, %ax ; int $0x80 * * WE DO NOT USE IT ANY MORE! It's only left here for historical * reasons and because gdb uses it as a signature to notice * signal handler stack frames. */ put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode); } put_user_catch(err); |
1da177e4c Linux-2.6.12-rc2 |
376 377 |
if (err) |
3d0aedd95 x86: signal: put ... |
378 |
return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
379 380 |
/* Set up registers for signal handler */ |
7e907f489 x86: clean up arc... |
381 382 |
regs->sp = (unsigned long)frame; regs->ip = (unsigned long)ka->sa.sa_handler; |
13ad7725e x86_32: signal: m... |
383 |
regs->ax = (unsigned long)sig; |
7e907f489 x86: clean up arc... |
384 385 |
regs->dx = (unsigned long)&frame->info; regs->cx = (unsigned long)&frame->uc; |
1da177e4c Linux-2.6.12-rc2 |
386 |
|
65ea5b034 x86: rename the s... |
387 388 389 390 |
regs->ds = __USER_DS; regs->es = __USER_DS; regs->ss = __USER_DS; regs->cs = __USER_CS; |
1da177e4c Linux-2.6.12-rc2 |
391 |
|
283828f3c [PATCH] Handle TI... |
392 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
393 |
} |
bfeb91a94 x86: signal: cosm... |
394 |
#else /* !CONFIG_X86_32 */ |
bfeb91a94 x86: signal: cosm... |
395 396 397 398 399 400 401 |
static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { struct rt_sigframe __user *frame; void __user *fp = NULL; int err = 0; struct task_struct *me = current; |
97286a2b6 x86: signal: intr... |
402 |
frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe), &fp); |
bfeb91a94 x86: signal: cosm... |
403 404 405 406 407 408 409 410 |
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) return -EFAULT; if (ka->sa.sa_flags & SA_SIGINFO) { if (copy_siginfo_to_user(&frame->info, info)) return -EFAULT; } |
98e3d45ed x86: signal: use ... |
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 |
put_user_try { /* Create the ucontext. */ if (cpu_has_xsave) put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); else put_user_ex(0, &frame->uc.uc_flags); put_user_ex(0, &frame->uc.uc_link); put_user_ex(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); put_user_ex(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags); put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Set up to return from userspace. If provided, use a stub already in userspace. */ /* x86-64 should always use SA_RESTORER. */ if (ka->sa.sa_flags & SA_RESTORER) { put_user_ex(ka->sa.sa_restorer, &frame->pretcode); } else { /* could use a vstub here */ err |= -EFAULT; } } put_user_catch(err); |
bfeb91a94 x86: signal: cosm... |
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
if (err) return -EFAULT; /* Set up registers for signal handler */ regs->di = sig; /* In case the signal handler was declared without prototypes */ regs->ax = 0; /* This also works for non SA_SIGINFO handlers because they expect the next argument after the signal number on the stack. */ regs->si = (unsigned long)&frame->info; regs->dx = (unsigned long)&frame->uc; regs->ip = (unsigned long) ka->sa.sa_handler; regs->sp = (unsigned long)frame; /* Set up the CS register to run signal handlers in 64-bit mode, even if the handler happens to be interrupting 32-bit code. */ regs->cs = __USER_CS; return 0; } #endif /* CONFIG_X86_32 */ |
e5fa2d063 x86: signal: unif... |
459 |
#ifdef CONFIG_X86_32 |
bfeb91a94 x86: signal: cosm... |
460 461 462 463 464 465 |
/* * Atomically swap in the new signal mask, and wait for a signal. */ asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) { |
3982294b0 x86, signals: Con... |
466 |
sigset_t blocked; |
bfeb91a94 x86: signal: cosm... |
467 |
current->saved_sigmask = current->blocked; |
3982294b0 x86, signals: Con... |
468 469 470 471 |
mask &= _BLOCKABLE; siginitset(&blocked, mask); set_current_blocked(&blocked); |
bfeb91a94 x86: signal: cosm... |
472 473 474 |
current->state = TASK_INTERRUPTIBLE; schedule(); |
bfeb91a94 x86: signal: cosm... |
475 |
|
3982294b0 x86, signals: Con... |
476 |
set_restore_sigmask(); |
bfeb91a94 x86: signal: cosm... |
477 478 479 480 481 482 483 484 |
return -ERESTARTNOHAND; } asmlinkage int sys_sigaction(int sig, const struct old_sigaction __user *act, struct old_sigaction __user *oact) { struct k_sigaction new_ka, old_ka; |
98e3d45ed x86: signal: use ... |
485 |
int ret = 0; |
bfeb91a94 x86: signal: cosm... |
486 487 488 |
if (act) { old_sigset_t mask; |
98e3d45ed x86: signal: use ... |
489 |
if (!access_ok(VERIFY_READ, act, sizeof(*act))) |
bfeb91a94 x86: signal: cosm... |
490 |
return -EFAULT; |
98e3d45ed x86: signal: use ... |
491 492 493 494 495 496 497 498 499 |
get_user_try { get_user_ex(new_ka.sa.sa_handler, &act->sa_handler); get_user_ex(new_ka.sa.sa_flags, &act->sa_flags); get_user_ex(mask, &act->sa_mask); get_user_ex(new_ka.sa.sa_restorer, &act->sa_restorer); } get_user_catch(ret); if (ret) return -EFAULT; |
bfeb91a94 x86: signal: cosm... |
500 501 502 503 504 505 |
siginitset(&new_ka.sa.sa_mask, mask); } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { |
98e3d45ed x86: signal: use ... |
506 |
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) |
bfeb91a94 x86: signal: cosm... |
507 |
return -EFAULT; |
98e3d45ed x86: signal: use ... |
508 509 510 511 512 513 514 515 516 |
put_user_try { put_user_ex(old_ka.sa.sa_handler, &oact->sa_handler); put_user_ex(old_ka.sa.sa_flags, &oact->sa_flags); put_user_ex(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); put_user_ex(old_ka.sa.sa_restorer, &oact->sa_restorer); } put_user_catch(ret); if (ret) return -EFAULT; |
bfeb91a94 x86: signal: cosm... |
517 518 519 520 |
} return ret; } |
e5fa2d063 x86: signal: unif... |
521 |
#endif /* CONFIG_X86_32 */ |
bfeb91a94 x86: signal: cosm... |
522 |
|
052acad48 x86: Merge sys_si... |
523 |
long |
bfeb91a94 x86: signal: cosm... |
524 525 526 527 528 |
sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, struct pt_regs *regs) { return do_sigaltstack(uss, uoss, regs->sp); } |
bfeb91a94 x86: signal: cosm... |
529 530 531 532 |
/* * Do a signal return; undo the signal stack. */ |
e5fa2d063 x86: signal: unif... |
533 |
#ifdef CONFIG_X86_32 |
b12bdaf11 x86: use regparm(... |
534 |
unsigned long sys_sigreturn(struct pt_regs *regs) |
bfeb91a94 x86: signal: cosm... |
535 536 |
{ struct sigframe __user *frame; |
bfeb91a94 x86: signal: cosm... |
537 538 |
unsigned long ax; sigset_t set; |
bfeb91a94 x86: signal: cosm... |
539 540 541 542 543 544 545 546 547 548 |
frame = (struct sigframe __user *)(regs->sp - 8); if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 && __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask)))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); |
3982294b0 x86, signals: Con... |
549 |
set_current_blocked(&set); |
bfeb91a94 x86: signal: cosm... |
550 551 552 553 554 555 |
if (restore_sigcontext(regs, &frame->sc, &ax)) goto badframe; return ax; badframe: |
ae417bb48 x86: signal: use ... |
556 |
signal_fault(regs, frame, "sigreturn"); |
bfeb91a94 x86: signal: cosm... |
557 558 559 |
return 0; } |
e5fa2d063 x86: signal: unif... |
560 |
#endif /* CONFIG_X86_32 */ |
bfeb91a94 x86: signal: cosm... |
561 |
|
744525092 x86: merge sys_rt... |
562 |
long sys_rt_sigreturn(struct pt_regs *regs) |
bfeb91a94 x86: signal: cosm... |
563 564 565 566 567 568 569 570 571 572 573 574 |
{ struct rt_sigframe __user *frame; unsigned long ax; sigset_t set; frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); |
e9bd3f0fa x86: signal: sys_... |
575 |
set_current_blocked(&set); |
bfeb91a94 x86: signal: cosm... |
576 577 578 579 580 581 582 583 584 585 586 587 588 |
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) goto badframe; if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) goto badframe; return ax; badframe: signal_fault(regs, frame, "rt_sigreturn"); return 0; } |
1da177e4c Linux-2.6.12-rc2 |
589 |
/* |
7e907f489 x86: clean up arc... |
590 591 |
* OK, we're invoking a handler: */ |
8d8c13bdb x86: signal_32.c:... |
592 593 |
static int signr_convert(int sig) { |
96bf84b71 x86: signal: cosm... |
594 |
#ifdef CONFIG_X86_32 |
8d8c13bdb x86: signal_32.c:... |
595 596 597 598 |
struct thread_info *info = current_thread_info(); if (info->exec_domain && info->exec_domain->signal_invmap && sig < 32) return info->exec_domain->signal_invmap[sig]; |
96bf84b71 x86: signal: cosm... |
599 |
#endif /* CONFIG_X86_32 */ |
8d8c13bdb x86: signal_32.c:... |
600 601 |
return sig; } |
cabf50358 x86: signal: cosm... |
602 |
#ifdef CONFIG_X86_32 |
455edbc42 x86: signal: intr... |
603 |
#define is_ia32 1 |
4694d2391 x86: signal_32.c:... |
604 605 |
#define ia32_setup_frame __setup_frame #define ia32_setup_rt_frame __setup_rt_frame |
455edbc42 x86: signal: intr... |
606 |
|
cabf50358 x86: signal: cosm... |
607 608 609 610 611 612 613 |
#else /* !CONFIG_X86_32 */ #ifdef CONFIG_IA32_EMULATION #define is_ia32 test_thread_flag(TIF_IA32) #else /* !CONFIG_IA32_EMULATION */ #define is_ia32 0 #endif /* CONFIG_IA32_EMULATION */ |
f5223763a x86: signal: move... |
614 615 616 617 |
int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs); int ia32_setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs); |
cabf50358 x86: signal: cosm... |
618 |
#endif /* CONFIG_X86_32 */ |
7c1def165 [PATCH] i386: nev... |
619 |
static int |
1d13024e6 x86: signal: spli... |
620 |
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
9b4296207 x86, do_signal: S... |
621 |
struct pt_regs *regs) |
1d13024e6 x86: signal: spli... |
622 |
{ |
8d8c13bdb x86: signal_32.c:... |
623 |
int usig = signr_convert(sig); |
9b4296207 x86, do_signal: S... |
624 |
sigset_t *set = ¤t->blocked; |
1d13024e6 x86: signal: spli... |
625 |
int ret; |
9b4296207 x86, do_signal: S... |
626 627 |
if (current_thread_info()->status & TS_RESTORE_SIGMASK) set = ¤t->saved_sigmask; |
1d13024e6 x86: signal: spli... |
628 |
/* Set up the stack frame */ |
455edbc42 x86: signal: intr... |
629 630 |
if (is_ia32) { if (ka->sa.sa_flags & SA_SIGINFO) |
4694d2391 x86: signal_32.c:... |
631 |
ret = ia32_setup_rt_frame(usig, ka, info, set, regs); |
455edbc42 x86: signal: intr... |
632 |
else |
4694d2391 x86: signal_32.c:... |
633 |
ret = ia32_setup_frame(usig, ka, set, regs); |
455edbc42 x86: signal: intr... |
634 635 |
} else ret = __setup_rt_frame(sig, ka, info, set, regs); |
1d13024e6 x86: signal: spli... |
636 |
|
3d0aedd95 x86: signal: put ... |
637 638 639 640 |
if (ret) { force_sigsegv(sig, current); return -EFAULT; } |
9b4296207 x86, do_signal: S... |
641 |
current_thread_info()->status &= ~TS_RESTORE_SIGMASK; |
1d13024e6 x86: signal: spli... |
642 643 644 645 |
return ret; } static int |
1da177e4c Linux-2.6.12-rc2 |
646 |
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
9b4296207 x86, do_signal: S... |
647 |
struct pt_regs *regs) |
1da177e4c Linux-2.6.12-rc2 |
648 |
{ |
7c1def165 [PATCH] i386: nev... |
649 |
int ret; |
1da177e4c Linux-2.6.12-rc2 |
650 |
/* Are we from a system call? */ |
bb57925f5 x86_32: signal: u... |
651 |
if (syscall_get_nr(current, regs) >= 0) { |
1da177e4c Linux-2.6.12-rc2 |
652 |
/* If so, check system call restarting.. */ |
bb57925f5 x86_32: signal: u... |
653 |
switch (syscall_get_error(current, regs)) { |
ac66f3fd8 x86: reduce trivi... |
654 655 656 657 658 659 660 |
case -ERESTART_RESTARTBLOCK: case -ERESTARTNOHAND: regs->ax = -EINTR; break; case -ERESTARTSYS: if (!(ka->sa.sa_flags & SA_RESTART)) { |
65ea5b034 x86: rename the s... |
661 |
regs->ax = -EINTR; |
1da177e4c Linux-2.6.12-rc2 |
662 |
break; |
ac66f3fd8 x86: reduce trivi... |
663 664 665 666 667 668 |
} /* fallthrough */ case -ERESTARTNOINTR: regs->ax = regs->orig_ax; regs->ip -= 2; break; |
1da177e4c Linux-2.6.12-rc2 |
669 670 671 672 |
} } /* |
e1f287735 x86 single_step: ... |
673 674 |
* If TF is set due to a debugger (TIF_FORCED_TF), clear the TF * flag so that register information in the sigcontext is correct. |
1da177e4c Linux-2.6.12-rc2 |
675 |
*/ |
65ea5b034 x86: rename the s... |
676 |
if (unlikely(regs->flags & X86_EFLAGS_TF) && |
e1f287735 x86 single_step: ... |
677 |
likely(test_and_clear_thread_flag(TIF_FORCED_TF))) |
65ea5b034 x86: rename the s... |
678 |
regs->flags &= ~X86_EFLAGS_TF; |
1da177e4c Linux-2.6.12-rc2 |
679 |
|
9b4296207 x86, do_signal: S... |
680 |
ret = setup_rt_frame(sig, ka, info, regs); |
1da177e4c Linux-2.6.12-rc2 |
681 |
|
7e907f489 x86: clean up arc... |
682 683 |
if (ret) return ret; |
7c1def165 [PATCH] i386: nev... |
684 |
|
8b9c5ff38 x86 signals: lift... |
685 686 687 688 689 690 691 692 693 694 695 696 |
/* * Clear the direction flag as per the ABI for function entry. */ regs->flags &= ~X86_EFLAGS_DF; /* * Clear TF when entering the signal handler, but * notify any tracer that was single-stepping it. * The tracer may want to single-step inside the * handler too. */ regs->flags &= ~X86_EFLAGS_TF; |
8b9c5ff38 x86 signals: lift... |
697 |
|
5e6292c0f signal: add block... |
698 |
block_sigmask(ka, sig); |
7e907f489 x86: clean up arc... |
699 |
|
36a033082 x86: tracehook_si... |
700 701 |
tracehook_signal_handler(sig, info, ka, regs, test_thread_flag(TIF_SINGLESTEP)); |
7e907f489 x86: clean up arc... |
702 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
703 |
} |
57917752f x86: signal: cosm... |
704 |
#ifdef CONFIG_X86_32 |
8fcd8e20f x86: signal: make... |
705 |
#define NR_restart_syscall __NR_restart_syscall |
57917752f x86: signal: cosm... |
706 707 708 709 |
#else /* !CONFIG_X86_32 */ #define NR_restart_syscall \ test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall #endif /* CONFIG_X86_32 */ |
1da177e4c Linux-2.6.12-rc2 |
710 711 712 713 714 |
/* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ |
75604d7f7 x86: remove all d... |
715 |
static void do_signal(struct pt_regs *regs) |
1da177e4c Linux-2.6.12-rc2 |
716 |
{ |
ac66f3fd8 x86: reduce trivi... |
717 |
struct k_sigaction ka; |
1da177e4c Linux-2.6.12-rc2 |
718 719 |
siginfo_t info; int signr; |
1da177e4c Linux-2.6.12-rc2 |
720 721 |
/* |
ac66f3fd8 x86: reduce trivi... |
722 723 724 725 726 |
* We want the common case to go fast, which is why we may in certain * cases get here from kernel mode. Just return without doing anything * if so. * X86_32: vm86 regs switched out by assembly code before reaching * here, so testing against kernel CS suffices. |
1da177e4c Linux-2.6.12-rc2 |
727 |
*/ |
717b594a4 [PATCH] xen: x86:... |
728 |
if (!user_mode(regs)) |
283828f3c [PATCH] Handle TI... |
729 |
return; |
1da177e4c Linux-2.6.12-rc2 |
730 |
|
1da177e4c Linux-2.6.12-rc2 |
731 732 |
signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { |
7e907f489 x86: clean up arc... |
733 |
/* Whee! Actually deliver the signal. */ |
9b4296207 x86, do_signal: S... |
734 |
handle_signal(signr, &info, &ka, regs); |
283828f3c [PATCH] Handle TI... |
735 |
return; |
1da177e4c Linux-2.6.12-rc2 |
736 |
} |
1da177e4c Linux-2.6.12-rc2 |
737 |
/* Did we come from a system call? */ |
bb57925f5 x86_32: signal: u... |
738 |
if (syscall_get_nr(current, regs) >= 0) { |
1da177e4c Linux-2.6.12-rc2 |
739 |
/* Restart the system call - no handlers present */ |
bb57925f5 x86_32: signal: u... |
740 |
switch (syscall_get_error(current, regs)) { |
283828f3c [PATCH] Handle TI... |
741 742 743 |
case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: |
65ea5b034 x86: rename the s... |
744 745 |
regs->ax = regs->orig_ax; regs->ip -= 2; |
283828f3c [PATCH] Handle TI... |
746 747 748 |
break; case -ERESTART_RESTARTBLOCK: |
8fcd8e20f x86: signal: make... |
749 |
regs->ax = NR_restart_syscall; |
65ea5b034 x86: rename the s... |
750 |
regs->ip -= 2; |
283828f3c [PATCH] Handle TI... |
751 |
break; |
1da177e4c Linux-2.6.12-rc2 |
752 753 |
} } |
283828f3c [PATCH] Handle TI... |
754 |
|
ac66f3fd8 x86: reduce trivi... |
755 756 757 758 |
/* * If there's no signal to deliver, we just put the saved sigmask * back. */ |
5a8da0ea8 signals: x86 TS_R... |
759 760 |
if (current_thread_info()->status & TS_RESTORE_SIGMASK) { current_thread_info()->status &= ~TS_RESTORE_SIGMASK; |
9b4296207 x86, do_signal: S... |
761 |
set_current_blocked(¤t->saved_sigmask); |
283828f3c [PATCH] Handle TI... |
762 |
} |
1da177e4c Linux-2.6.12-rc2 |
763 764 765 766 |
} /* * notification of userspace execution resumption |
283828f3c [PATCH] Handle TI... |
767 |
* - triggered by the TIF_WORK_MASK flags |
1da177e4c Linux-2.6.12-rc2 |
768 |
*/ |
7e907f489 x86: clean up arc... |
769 770 |
void do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) |
1da177e4c Linux-2.6.12-rc2 |
771 |
{ |
c1ebf8356 x86: mce: Rename ... |
772 |
#ifdef CONFIG_X86_MCE |
ee847c54b x86: signal: cosm... |
773 774 |
/* notify userspace of pending MCEs */ if (thread_info_flags & _TIF_MCE_NOTIFY) |
9b1beaf2b x86, mce: support... |
775 |
mce_notify_process(); |
ee847c54b x86: signal: cosm... |
776 |
#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ |
1da177e4c Linux-2.6.12-rc2 |
777 |
/* deal with pending signal delivery */ |
5a8da0ea8 signals: x86 TS_R... |
778 |
if (thread_info_flags & _TIF_SIGPENDING) |
283828f3c [PATCH] Handle TI... |
779 |
do_signal(regs); |
8f4d37ec0 sched: high-res p... |
780 |
|
59e52130f x86: tracehook: T... |
781 782 783 |
if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); |
ee18d64c1 KEYS: Add a keyct... |
784 785 |
if (current->replacement_session_keyring) key_replace_session_keyring(); |
59e52130f x86: tracehook: T... |
786 |
} |
7c68af6e3 core, x86: Add us... |
787 788 |
if (thread_info_flags & _TIF_USER_RETURN_NOTIFY) fire_user_return_notifiers(); |
59e52130f x86: tracehook: T... |
789 |
|
ee847c54b x86: signal: cosm... |
790 |
#ifdef CONFIG_X86_32 |
1da177e4c Linux-2.6.12-rc2 |
791 |
clear_thread_flag(TIF_IRET); |
ee847c54b x86: signal: cosm... |
792 |
#endif /* CONFIG_X86_32 */ |
1da177e4c Linux-2.6.12-rc2 |
793 |
} |
72fa50f4e x86_32: signal: i... |
794 795 796 797 798 799 |
void signal_fault(struct pt_regs *regs, void __user *frame, char *where) { struct task_struct *me = current; if (show_unhandled_signals && printk_ratelimit()) { |
ae417bb48 x86: signal: use ... |
800 |
printk("%s" |
72fa50f4e x86_32: signal: i... |
801 |
"%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx", |
ae417bb48 x86: signal: use ... |
802 |
task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG, |
72fa50f4e x86_32: signal: i... |
803 804 805 806 807 808 809 810 811 |
me->comm, me->pid, where, frame, regs->ip, regs->sp, regs->orig_ax); print_vma_addr(" in ", regs->ip); printk(KERN_CONT " "); } force_sig(SIGSEGV, me); } |