diff options
Diffstat (limited to 'arch/x86/ia32/ia32_signal.c')
-rw-r--r-- | arch/x86/ia32/ia32_signal.c | 110 |
1 files changed, 38 insertions, 72 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 4bc02b23674b..9dabd00e9805 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c | |||
@@ -24,13 +24,14 @@ | |||
24 | #include <asm/ucontext.h> | 24 | #include <asm/ucontext.h> |
25 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
26 | #include <asm/i387.h> | 26 | #include <asm/i387.h> |
27 | #include <asm/ia32.h> | ||
28 | #include <asm/ptrace.h> | 27 | #include <asm/ptrace.h> |
29 | #include <asm/ia32_unistd.h> | 28 | #include <asm/ia32_unistd.h> |
30 | #include <asm/user32.h> | 29 | #include <asm/user32.h> |
31 | #include <asm/sigcontext32.h> | 30 | #include <asm/sigcontext32.h> |
32 | #include <asm/proto.h> | 31 | #include <asm/proto.h> |
33 | #include <asm/vdso.h> | 32 | #include <asm/vdso.h> |
33 | #include <asm/sigframe.h> | ||
34 | #include <asm/sys_ia32.h> | ||
34 | 35 | ||
35 | #define DEBUG_SIG 0 | 36 | #define DEBUG_SIG 0 |
36 | 37 | ||
@@ -41,7 +42,6 @@ | |||
41 | X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \ | 42 | X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \ |
42 | X86_EFLAGS_CF) | 43 | X86_EFLAGS_CF) |
43 | 44 | ||
44 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); | ||
45 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where); | 45 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where); |
46 | 46 | ||
47 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) | 47 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) |
@@ -173,47 +173,28 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr, | |||
173 | /* | 173 | /* |
174 | * Do a signal return; undo the signal stack. | 174 | * Do a signal return; undo the signal stack. |
175 | */ | 175 | */ |
176 | #define COPY(x) { \ | ||
177 | err |= __get_user(regs->x, &sc->x); \ | ||
178 | } | ||
176 | 179 | ||
177 | struct sigframe | 180 | #define COPY_SEG_CPL3(seg) { \ |
178 | { | 181 | unsigned short tmp; \ |
179 | u32 pretcode; | 182 | err |= __get_user(tmp, &sc->seg); \ |
180 | int sig; | 183 | regs->seg = tmp | 3; \ |
181 | struct sigcontext_ia32 sc; | ||
182 | struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */ | ||
183 | unsigned int extramask[_COMPAT_NSIG_WORDS-1]; | ||
184 | char retcode[8]; | ||
185 | /* fp state follows here */ | ||
186 | }; | ||
187 | |||
188 | struct rt_sigframe | ||
189 | { | ||
190 | u32 pretcode; | ||
191 | int sig; | ||
192 | u32 pinfo; | ||
193 | u32 puc; | ||
194 | compat_siginfo_t info; | ||
195 | struct ucontext_ia32 uc; | ||
196 | char retcode[8]; | ||
197 | /* fp state follows here */ | ||
198 | }; | ||
199 | |||
200 | #define COPY(x) { \ | ||
201 | unsigned int reg; \ | ||
202 | err |= __get_user(reg, &sc->x); \ | ||
203 | regs->x = reg; \ | ||
204 | } | 184 | } |
205 | 185 | ||
206 | #define RELOAD_SEG(seg,mask) \ | 186 | #define RELOAD_SEG(seg) { \ |
207 | { unsigned int cur; \ | 187 | unsigned int cur, pre; \ |
208 | unsigned short pre; \ | 188 | err |= __get_user(pre, &sc->seg); \ |
209 | err |= __get_user(pre, &sc->seg); \ | 189 | savesegment(seg, cur); \ |
210 | savesegment(seg, cur); \ | 190 | pre |= 3; \ |
211 | pre |= mask; \ | 191 | if (pre != cur) \ |
212 | if (pre != cur) loadsegment(seg, pre); } | 192 | loadsegment(seg, pre); \ |
193 | } | ||
213 | 194 | ||
214 | static int ia32_restore_sigcontext(struct pt_regs *regs, | 195 | static int ia32_restore_sigcontext(struct pt_regs *regs, |
215 | struct sigcontext_ia32 __user *sc, | 196 | struct sigcontext_ia32 __user *sc, |
216 | unsigned int *peax) | 197 | unsigned int *pax) |
217 | { | 198 | { |
218 | unsigned int tmpflags, gs, oldgs, err = 0; | 199 | unsigned int tmpflags, gs, oldgs, err = 0; |
219 | void __user *buf; | 200 | void __user *buf; |
@@ -240,18 +221,16 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, | |||
240 | if (gs != oldgs) | 221 | if (gs != oldgs) |
241 | load_gs_index(gs); | 222 | load_gs_index(gs); |
242 | 223 | ||
243 | RELOAD_SEG(fs, 3); | 224 | RELOAD_SEG(fs); |
244 | RELOAD_SEG(ds, 3); | 225 | RELOAD_SEG(ds); |
245 | RELOAD_SEG(es, 3); | 226 | RELOAD_SEG(es); |
246 | 227 | ||
247 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); | 228 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
248 | COPY(dx); COPY(cx); COPY(ip); | 229 | COPY(dx); COPY(cx); COPY(ip); |
249 | /* Don't touch extended registers */ | 230 | /* Don't touch extended registers */ |
250 | 231 | ||
251 | err |= __get_user(regs->cs, &sc->cs); | 232 | COPY_SEG_CPL3(cs); |
252 | regs->cs |= 3; | 233 | COPY_SEG_CPL3(ss); |
253 | err |= __get_user(regs->ss, &sc->ss); | ||
254 | regs->ss |= 3; | ||
255 | 234 | ||
256 | err |= __get_user(tmpflags, &sc->flags); | 235 | err |= __get_user(tmpflags, &sc->flags); |
257 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); | 236 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); |
@@ -262,15 +241,13 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, | |||
262 | buf = compat_ptr(tmp); | 241 | buf = compat_ptr(tmp); |
263 | err |= restore_i387_xstate_ia32(buf); | 242 | err |= restore_i387_xstate_ia32(buf); |
264 | 243 | ||
265 | err |= __get_user(tmp, &sc->ax); | 244 | err |= __get_user(*pax, &sc->ax); |
266 | *peax = tmp; | ||
267 | |||
268 | return err; | 245 | return err; |
269 | } | 246 | } |
270 | 247 | ||
271 | asmlinkage long sys32_sigreturn(struct pt_regs *regs) | 248 | asmlinkage long sys32_sigreturn(struct pt_regs *regs) |
272 | { | 249 | { |
273 | struct sigframe __user *frame = (struct sigframe __user *)(regs->sp-8); | 250 | struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8); |
274 | sigset_t set; | 251 | sigset_t set; |
275 | unsigned int ax; | 252 | unsigned int ax; |
276 | 253 | ||
@@ -300,12 +277,12 @@ badframe: | |||
300 | 277 | ||
301 | asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) | 278 | asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) |
302 | { | 279 | { |
303 | struct rt_sigframe __user *frame; | 280 | struct rt_sigframe_ia32 __user *frame; |
304 | sigset_t set; | 281 | sigset_t set; |
305 | unsigned int ax; | 282 | unsigned int ax; |
306 | struct pt_regs tregs; | 283 | struct pt_regs tregs; |
307 | 284 | ||
308 | frame = (struct rt_sigframe __user *)(regs->sp - 4); | 285 | frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4); |
309 | 286 | ||
310 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 287 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
311 | goto badframe; | 288 | goto badframe; |
@@ -359,20 +336,15 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | |||
359 | err |= __put_user(regs->dx, &sc->dx); | 336 | err |= __put_user(regs->dx, &sc->dx); |
360 | err |= __put_user(regs->cx, &sc->cx); | 337 | err |= __put_user(regs->cx, &sc->cx); |
361 | err |= __put_user(regs->ax, &sc->ax); | 338 | err |= __put_user(regs->ax, &sc->ax); |
362 | err |= __put_user(regs->cs, &sc->cs); | ||
363 | err |= __put_user(regs->ss, &sc->ss); | ||
364 | err |= __put_user(current->thread.trap_no, &sc->trapno); | 339 | err |= __put_user(current->thread.trap_no, &sc->trapno); |
365 | err |= __put_user(current->thread.error_code, &sc->err); | 340 | err |= __put_user(current->thread.error_code, &sc->err); |
366 | err |= __put_user(regs->ip, &sc->ip); | 341 | err |= __put_user(regs->ip, &sc->ip); |
342 | err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs); | ||
367 | err |= __put_user(regs->flags, &sc->flags); | 343 | err |= __put_user(regs->flags, &sc->flags); |
368 | err |= __put_user(regs->sp, &sc->sp_at_signal); | 344 | err |= __put_user(regs->sp, &sc->sp_at_signal); |
345 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); | ||
369 | 346 | ||
370 | tmp = save_i387_xstate_ia32(fpstate); | 347 | err |= __put_user(ptr_to_compat(fpstate), &sc->fpstate); |
371 | if (tmp < 0) | ||
372 | err = -EFAULT; | ||
373 | else | ||
374 | err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL), | ||
375 | &sc->fpstate); | ||
376 | 348 | ||
377 | /* non-iBCS2 extensions.. */ | 349 | /* non-iBCS2 extensions.. */ |
378 | err |= __put_user(mask, &sc->oldmask); | 350 | err |= __put_user(mask, &sc->oldmask); |
@@ -400,7 +372,7 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
400 | } | 372 | } |
401 | 373 | ||
402 | /* This is the legacy signal stack switching. */ | 374 | /* This is the legacy signal stack switching. */ |
403 | else if ((regs->ss & 0xffff) != __USER_DS && | 375 | else if ((regs->ss & 0xffff) != __USER32_DS && |
404 | !(ka->sa.sa_flags & SA_RESTORER) && | 376 | !(ka->sa.sa_flags & SA_RESTORER) && |
405 | ka->sa.sa_restorer) | 377 | ka->sa.sa_restorer) |
406 | sp = (unsigned long) ka->sa.sa_restorer; | 378 | sp = (unsigned long) ka->sa.sa_restorer; |
@@ -408,6 +380,8 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
408 | if (used_math()) { | 380 | if (used_math()) { |
409 | sp = sp - sig_xstate_ia32_size; | 381 | sp = sp - sig_xstate_ia32_size; |
410 | *fpstate = (struct _fpstate_ia32 *) sp; | 382 | *fpstate = (struct _fpstate_ia32 *) sp; |
383 | if (save_i387_xstate_ia32(*fpstate) < 0) | ||
384 | return (void __user *) -1L; | ||
411 | } | 385 | } |
412 | 386 | ||
413 | sp -= frame_size; | 387 | sp -= frame_size; |
@@ -420,7 +394,7 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
420 | int ia32_setup_frame(int sig, struct k_sigaction *ka, | 394 | int ia32_setup_frame(int sig, struct k_sigaction *ka, |
421 | compat_sigset_t *set, struct pt_regs *regs) | 395 | compat_sigset_t *set, struct pt_regs *regs) |
422 | { | 396 | { |
423 | struct sigframe __user *frame; | 397 | struct sigframe_ia32 __user *frame; |
424 | void __user *restorer; | 398 | void __user *restorer; |
425 | int err = 0; | 399 | int err = 0; |
426 | void __user *fpstate = NULL; | 400 | void __user *fpstate = NULL; |
@@ -430,12 +404,10 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
430 | u16 poplmovl; | 404 | u16 poplmovl; |
431 | u32 val; | 405 | u32 val; |
432 | u16 int80; | 406 | u16 int80; |
433 | u16 pad; | ||
434 | } __attribute__((packed)) code = { | 407 | } __attribute__((packed)) code = { |
435 | 0xb858, /* popl %eax ; movl $...,%eax */ | 408 | 0xb858, /* popl %eax ; movl $...,%eax */ |
436 | __NR_ia32_sigreturn, | 409 | __NR_ia32_sigreturn, |
437 | 0x80cd, /* int $0x80 */ | 410 | 0x80cd, /* int $0x80 */ |
438 | 0, | ||
439 | }; | 411 | }; |
440 | 412 | ||
441 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); | 413 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
@@ -471,7 +443,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
471 | * These are actually not used anymore, but left because some | 443 | * These are actually not used anymore, but left because some |
472 | * gdb versions depend on them as a marker. | 444 | * gdb versions depend on them as a marker. |
473 | */ | 445 | */ |
474 | err |= __copy_to_user(frame->retcode, &code, 8); | 446 | err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode); |
475 | if (err) | 447 | if (err) |
476 | return -EFAULT; | 448 | return -EFAULT; |
477 | 449 | ||
@@ -501,7 +473,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
501 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 473 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
502 | compat_sigset_t *set, struct pt_regs *regs) | 474 | compat_sigset_t *set, struct pt_regs *regs) |
503 | { | 475 | { |
504 | struct rt_sigframe __user *frame; | 476 | struct rt_sigframe_ia32 __user *frame; |
505 | void __user *restorer; | 477 | void __user *restorer; |
506 | int err = 0; | 478 | int err = 0; |
507 | void __user *fpstate = NULL; | 479 | void __user *fpstate = NULL; |
@@ -511,8 +483,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
511 | u8 movl; | 483 | u8 movl; |
512 | u32 val; | 484 | u32 val; |
513 | u16 int80; | 485 | u16 int80; |
514 | u16 pad; | 486 | u8 pad; |
515 | u8 pad2; | ||
516 | } __attribute__((packed)) code = { | 487 | } __attribute__((packed)) code = { |
517 | 0xb8, | 488 | 0xb8, |
518 | __NR_ia32_rt_sigreturn, | 489 | __NR_ia32_rt_sigreturn, |
@@ -559,7 +530,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
559 | * Not actually used anymore, but left because some gdb | 530 | * Not actually used anymore, but left because some gdb |
560 | * versions need it. | 531 | * versions need it. |
561 | */ | 532 | */ |
562 | err |= __copy_to_user(frame->retcode, &code, 8); | 533 | err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode); |
563 | if (err) | 534 | if (err) |
564 | return -EFAULT; | 535 | return -EFAULT; |
565 | 536 | ||
@@ -572,11 +543,6 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
572 | regs->dx = (unsigned long) &frame->info; | 543 | regs->dx = (unsigned long) &frame->info; |
573 | regs->cx = (unsigned long) &frame->uc; | 544 | regs->cx = (unsigned long) &frame->uc; |
574 | 545 | ||
575 | /* Make -mregparm=3 work */ | ||
576 | regs->ax = sig; | ||
577 | regs->dx = (unsigned long) &frame->info; | ||
578 | regs->cx = (unsigned long) &frame->uc; | ||
579 | |||
580 | loadsegment(ds, __USER32_DS); | 546 | loadsegment(ds, __USER32_DS); |
581 | loadsegment(es, __USER32_DS); | 547 | loadsegment(es, __USER32_DS); |
582 | 548 | ||