diff options
Diffstat (limited to 'arch/x86/kernel/ptrace.c')
-rw-r--r-- | arch/x86/kernel/ptrace.c | 65 |
1 files changed, 35 insertions, 30 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index c709868d28a5..7161d60e152d 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -463,12 +463,13 @@ static int ptrace_set_debugreg(struct task_struct *child, | |||
463 | void ptrace_disable(struct task_struct *child) | 463 | void ptrace_disable(struct task_struct *child) |
464 | { | 464 | { |
465 | user_disable_single_step(child); | 465 | user_disable_single_step(child); |
466 | #ifdef TIF_SYSCALL_EMU | ||
466 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); | 467 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); |
468 | #endif | ||
467 | } | 469 | } |
468 | 470 | ||
469 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 471 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) |
470 | { | 472 | { |
471 | struct user * dummy = NULL; | ||
472 | int i, ret; | 473 | int i, ret; |
473 | unsigned long __user *datap = (unsigned long __user *)data; | 474 | unsigned long __user *datap = (unsigned long __user *)data; |
474 | 475 | ||
@@ -484,18 +485,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
484 | unsigned long tmp; | 485 | unsigned long tmp; |
485 | 486 | ||
486 | ret = -EIO; | 487 | ret = -EIO; |
487 | if ((addr & 3) || addr < 0 || | 488 | if ((addr & (sizeof(data) - 1)) || addr < 0 || |
488 | addr > sizeof(struct user) - 3) | 489 | addr >= sizeof(struct user)) |
489 | break; | 490 | break; |
490 | 491 | ||
491 | tmp = 0; /* Default return condition */ | 492 | tmp = 0; /* Default return condition */ |
492 | if(addr < FRAME_SIZE*sizeof(long)) | 493 | if (addr < sizeof(struct user_regs_struct)) |
493 | tmp = getreg(child, addr); | 494 | tmp = getreg(child, addr); |
494 | if(addr >= (long) &dummy->u_debugreg[0] && | 495 | else if (addr >= offsetof(struct user, u_debugreg[0]) && |
495 | addr <= (long) &dummy->u_debugreg[7]){ | 496 | addr <= offsetof(struct user, u_debugreg[7])) { |
496 | addr -= (long) &dummy->u_debugreg[0]; | 497 | addr -= offsetof(struct user, u_debugreg[0]); |
497 | addr = addr >> 2; | 498 | tmp = ptrace_get_debugreg(child, addr / sizeof(data)); |
498 | tmp = ptrace_get_debugreg(child, addr); | ||
499 | } | 499 | } |
500 | ret = put_user(tmp, datap); | 500 | ret = put_user(tmp, datap); |
501 | break; | 501 | break; |
@@ -509,34 +509,26 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
509 | 509 | ||
510 | case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ | 510 | case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ |
511 | ret = -EIO; | 511 | ret = -EIO; |
512 | if ((addr & 3) || addr < 0 || | 512 | if ((addr & (sizeof(data) - 1)) || addr < 0 || |
513 | addr > sizeof(struct user) - 3) | 513 | addr >= sizeof(struct user)) |
514 | break; | 514 | break; |
515 | 515 | ||
516 | if (addr < FRAME_SIZE*sizeof(long)) { | 516 | if (addr < sizeof(struct user_regs_struct)) |
517 | ret = putreg(child, addr, data); | 517 | ret = putreg(child, addr, data); |
518 | break; | 518 | else if (addr >= offsetof(struct user, u_debugreg[0]) && |
519 | addr <= offsetof(struct user, u_debugreg[7])) { | ||
520 | addr -= offsetof(struct user, u_debugreg[0]); | ||
521 | ret = ptrace_set_debugreg(child, | ||
522 | addr / sizeof(data), data); | ||
519 | } | 523 | } |
520 | /* We need to be very careful here. We implicitly | 524 | break; |
521 | want to modify a portion of the task_struct, and we | ||
522 | have to be selective about what portions we allow someone | ||
523 | to modify. */ | ||
524 | |||
525 | ret = -EIO; | ||
526 | if(addr >= (long) &dummy->u_debugreg[0] && | ||
527 | addr <= (long) &dummy->u_debugreg[7]){ | ||
528 | addr -= (long) &dummy->u_debugreg; | ||
529 | addr = addr >> 2; | ||
530 | ret = ptrace_set_debugreg(child, addr, data); | ||
531 | } | ||
532 | break; | ||
533 | 525 | ||
534 | case PTRACE_GETREGS: { /* Get all gp regs from the child. */ | 526 | case PTRACE_GETREGS: { /* Get all gp regs from the child. */ |
535 | if (!access_ok(VERIFY_WRITE, datap, FRAME_SIZE*sizeof(long))) { | 527 | if (!access_ok(VERIFY_WRITE, datap, sizeof(struct user_regs_struct))) { |
536 | ret = -EIO; | 528 | ret = -EIO; |
537 | break; | 529 | break; |
538 | } | 530 | } |
539 | for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) { | 531 | for (i = 0; i < sizeof(struct user_regs_struct); i += sizeof(long)) { |
540 | __put_user(getreg(child, i), datap); | 532 | __put_user(getreg(child, i), datap); |
541 | datap++; | 533 | datap++; |
542 | } | 534 | } |
@@ -546,11 +538,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
546 | 538 | ||
547 | case PTRACE_SETREGS: { /* Set all gp regs in the child. */ | 539 | case PTRACE_SETREGS: { /* Set all gp regs in the child. */ |
548 | unsigned long tmp; | 540 | unsigned long tmp; |
549 | if (!access_ok(VERIFY_READ, datap, FRAME_SIZE*sizeof(long))) { | 541 | if (!access_ok(VERIFY_READ, datap, sizeof(struct user_regs_struct))) { |
550 | ret = -EIO; | 542 | ret = -EIO; |
551 | break; | 543 | break; |
552 | } | 544 | } |
553 | for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) { | 545 | for (i = 0; i < sizeof(struct user_regs_struct); i += sizeof(long)) { |
554 | __get_user(tmp, datap); | 546 | __get_user(tmp, datap); |
555 | putreg(child, i, tmp); | 547 | putreg(child, i, tmp); |
556 | datap++; | 548 | datap++; |
@@ -584,6 +576,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
584 | break; | 576 | break; |
585 | } | 577 | } |
586 | 578 | ||
579 | #ifdef CONFIG_X86_32 | ||
587 | case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */ | 580 | case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */ |
588 | if (!access_ok(VERIFY_WRITE, datap, | 581 | if (!access_ok(VERIFY_WRITE, datap, |
589 | sizeof(struct user_fxsr_struct))) { | 582 | sizeof(struct user_fxsr_struct))) { |
@@ -606,7 +599,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
606 | ret = set_fpxregs(child, (struct user_fxsr_struct __user *)data); | 599 | ret = set_fpxregs(child, (struct user_fxsr_struct __user *)data); |
607 | break; | 600 | break; |
608 | } | 601 | } |
602 | #endif | ||
609 | 603 | ||
604 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION | ||
610 | case PTRACE_GET_THREAD_AREA: | 605 | case PTRACE_GET_THREAD_AREA: |
611 | if (addr < 0) | 606 | if (addr < 0) |
612 | return -EIO; | 607 | return -EIO; |
@@ -620,6 +615,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
620 | ret = do_set_thread_area(child, addr, | 615 | ret = do_set_thread_area(child, addr, |
621 | (struct user_desc __user *) data, 0); | 616 | (struct user_desc __user *) data, 0); |
622 | break; | 617 | break; |
618 | #endif | ||
619 | |||
620 | #ifdef CONFIG_X86_64 | ||
621 | /* normal 64bit interface to access TLS data. | ||
622 | Works just like arch_prctl, except that the arguments | ||
623 | are reversed. */ | ||
624 | case PTRACE_ARCH_PRCTL: | ||
625 | ret = do_arch_prctl(child, data, addr); | ||
626 | break; | ||
627 | #endif | ||
623 | 628 | ||
624 | default: | 629 | default: |
625 | ret = ptrace_request(child, request, addr, data); | 630 | ret = ptrace_request(child, request, addr, data); |