| .. | .. |
|---|
| 26 | 26 | #include <linux/audit.h> |
|---|
| 27 | 27 | |
|---|
| 28 | 28 | #include <linux/uaccess.h> |
|---|
| 29 | | -#include <asm/pgtable.h> |
|---|
| 30 | 29 | #include <asm/processor.h> |
|---|
| 31 | 30 | #include <asm/asm-offsets.h> |
|---|
| 32 | 31 | |
|---|
| .. | .. |
|---|
| 88 | 87 | ptrace_disable(task); |
|---|
| 89 | 88 | /* Don't wake up the task, but let the |
|---|
| 90 | 89 | parent know something happened. */ |
|---|
| 91 | | - force_sig_fault(SIGTRAP, TRAP_TRACE, |
|---|
| 92 | | - (void __user *) (task_regs(task)->iaoq[0] & ~3), |
|---|
| 93 | | - task); |
|---|
| 90 | + force_sig_fault_to_task(SIGTRAP, TRAP_TRACE, |
|---|
| 91 | + (void __user *) (task_regs(task)->iaoq[0] & ~3), |
|---|
| 92 | + task); |
|---|
| 94 | 93 | /* notify_parent(task, SIGCHLD); */ |
|---|
| 95 | 94 | return; |
|---|
| 96 | 95 | } |
|---|
| .. | .. |
|---|
| 127 | 126 | unsigned long __user *datap = (unsigned long __user *)data; |
|---|
| 128 | 127 | unsigned long tmp; |
|---|
| 129 | 128 | long ret = -EIO; |
|---|
| 129 | + |
|---|
| 130 | + unsigned long user_regs_struct_size = sizeof(struct user_regs_struct); |
|---|
| 131 | +#ifdef CONFIG_64BIT |
|---|
| 132 | + if (is_compat_task()) |
|---|
| 133 | + user_regs_struct_size /= 2; |
|---|
| 134 | +#endif |
|---|
| 130 | 135 | |
|---|
| 131 | 136 | switch (request) { |
|---|
| 132 | 137 | |
|---|
| .. | .. |
|---|
| 183 | 188 | return copy_regset_to_user(child, |
|---|
| 184 | 189 | task_user_regset_view(current), |
|---|
| 185 | 190 | REGSET_GENERAL, |
|---|
| 186 | | - 0, sizeof(struct user_regs_struct), |
|---|
| 191 | + 0, user_regs_struct_size, |
|---|
| 187 | 192 | datap); |
|---|
| 188 | 193 | |
|---|
| 189 | 194 | case PTRACE_SETREGS: /* Set all gp regs in the child. */ |
|---|
| 190 | 195 | return copy_regset_from_user(child, |
|---|
| 191 | 196 | task_user_regset_view(current), |
|---|
| 192 | 197 | REGSET_GENERAL, |
|---|
| 193 | | - 0, sizeof(struct user_regs_struct), |
|---|
| 198 | + 0, user_regs_struct_size, |
|---|
| 194 | 199 | datap); |
|---|
| 195 | 200 | |
|---|
| 196 | 201 | case PTRACE_GETFPREGS: /* Get the child FPU state. */ |
|---|
| .. | .. |
|---|
| 304 | 309 | } |
|---|
| 305 | 310 | } |
|---|
| 306 | 311 | break; |
|---|
| 312 | + case PTRACE_GETREGS: |
|---|
| 313 | + case PTRACE_SETREGS: |
|---|
| 314 | + case PTRACE_GETFPREGS: |
|---|
| 315 | + case PTRACE_SETFPREGS: |
|---|
| 316 | + return arch_ptrace(child, request, addr, data); |
|---|
| 307 | 317 | |
|---|
| 308 | 318 | default: |
|---|
| 309 | 319 | ret = compat_ptrace_request(child, request, addr, data); |
|---|
| .. | .. |
|---|
| 342 | 352 | } |
|---|
| 343 | 353 | |
|---|
| 344 | 354 | /* Do the secure computing check after ptrace. */ |
|---|
| 345 | | - if (secure_computing(NULL) == -1) |
|---|
| 355 | + if (secure_computing() == -1) |
|---|
| 346 | 356 | return -1; |
|---|
| 347 | 357 | |
|---|
| 348 | 358 | #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS |
|---|
| .. | .. |
|---|
| 392 | 402 | |
|---|
| 393 | 403 | static int fpr_get(struct task_struct *target, |
|---|
| 394 | 404 | const struct user_regset *regset, |
|---|
| 395 | | - unsigned int pos, unsigned int count, |
|---|
| 396 | | - void *kbuf, void __user *ubuf) |
|---|
| 405 | + struct membuf to) |
|---|
| 397 | 406 | { |
|---|
| 398 | 407 | struct pt_regs *regs = task_regs(target); |
|---|
| 399 | | - __u64 *k = kbuf; |
|---|
| 400 | | - __u64 __user *u = ubuf; |
|---|
| 401 | | - __u64 reg; |
|---|
| 402 | 408 | |
|---|
| 403 | | - pos /= sizeof(reg); |
|---|
| 404 | | - count /= sizeof(reg); |
|---|
| 405 | | - |
|---|
| 406 | | - if (kbuf) |
|---|
| 407 | | - for (; count > 0 && pos < ELF_NFPREG; --count) |
|---|
| 408 | | - *k++ = regs->fr[pos++]; |
|---|
| 409 | | - else |
|---|
| 410 | | - for (; count > 0 && pos < ELF_NFPREG; --count) |
|---|
| 411 | | - if (__put_user(regs->fr[pos++], u++)) |
|---|
| 412 | | - return -EFAULT; |
|---|
| 413 | | - |
|---|
| 414 | | - kbuf = k; |
|---|
| 415 | | - ubuf = u; |
|---|
| 416 | | - pos *= sizeof(reg); |
|---|
| 417 | | - count *= sizeof(reg); |
|---|
| 418 | | - return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
|---|
| 419 | | - ELF_NFPREG * sizeof(reg), -1); |
|---|
| 409 | + return membuf_write(&to, regs->fr, ELF_NFPREG * sizeof(__u64)); |
|---|
| 420 | 410 | } |
|---|
| 421 | 411 | |
|---|
| 422 | 412 | static int fpr_set(struct task_struct *target, |
|---|
| .. | .. |
|---|
| 528 | 518 | |
|---|
| 529 | 519 | static int gpr_get(struct task_struct *target, |
|---|
| 530 | 520 | const struct user_regset *regset, |
|---|
| 531 | | - unsigned int pos, unsigned int count, |
|---|
| 532 | | - void *kbuf, void __user *ubuf) |
|---|
| 521 | + struct membuf to) |
|---|
| 533 | 522 | { |
|---|
| 534 | 523 | struct pt_regs *regs = task_regs(target); |
|---|
| 535 | | - unsigned long *k = kbuf; |
|---|
| 536 | | - unsigned long __user *u = ubuf; |
|---|
| 537 | | - unsigned long reg; |
|---|
| 524 | + unsigned int pos; |
|---|
| 538 | 525 | |
|---|
| 539 | | - pos /= sizeof(reg); |
|---|
| 540 | | - count /= sizeof(reg); |
|---|
| 541 | | - |
|---|
| 542 | | - if (kbuf) |
|---|
| 543 | | - for (; count > 0 && pos < ELF_NGREG; --count) |
|---|
| 544 | | - *k++ = get_reg(regs, pos++); |
|---|
| 545 | | - else |
|---|
| 546 | | - for (; count > 0 && pos < ELF_NGREG; --count) |
|---|
| 547 | | - if (__put_user(get_reg(regs, pos++), u++)) |
|---|
| 548 | | - return -EFAULT; |
|---|
| 549 | | - kbuf = k; |
|---|
| 550 | | - ubuf = u; |
|---|
| 551 | | - pos *= sizeof(reg); |
|---|
| 552 | | - count *= sizeof(reg); |
|---|
| 553 | | - return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
|---|
| 554 | | - ELF_NGREG * sizeof(reg), -1); |
|---|
| 526 | + for (pos = 0; pos < ELF_NGREG; pos++) |
|---|
| 527 | + membuf_store(&to, get_reg(regs, pos)); |
|---|
| 528 | + return 0; |
|---|
| 555 | 529 | } |
|---|
| 556 | 530 | |
|---|
| 557 | 531 | static int gpr_set(struct task_struct *target, |
|---|
| .. | .. |
|---|
| 589 | 563 | [REGSET_GENERAL] = { |
|---|
| 590 | 564 | .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, |
|---|
| 591 | 565 | .size = sizeof(long), .align = sizeof(long), |
|---|
| 592 | | - .get = gpr_get, .set = gpr_set |
|---|
| 566 | + .regset_get = gpr_get, .set = gpr_set |
|---|
| 593 | 567 | }, |
|---|
| 594 | 568 | [REGSET_FP] = { |
|---|
| 595 | 569 | .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, |
|---|
| 596 | 570 | .size = sizeof(__u64), .align = sizeof(__u64), |
|---|
| 597 | | - .get = fpr_get, .set = fpr_set |
|---|
| 571 | + .regset_get = fpr_get, .set = fpr_set |
|---|
| 598 | 572 | } |
|---|
| 599 | 573 | }; |
|---|
| 600 | 574 | |
|---|
| .. | .. |
|---|
| 608 | 582 | |
|---|
| 609 | 583 | static int gpr32_get(struct task_struct *target, |
|---|
| 610 | 584 | const struct user_regset *regset, |
|---|
| 611 | | - unsigned int pos, unsigned int count, |
|---|
| 612 | | - void *kbuf, void __user *ubuf) |
|---|
| 585 | + struct membuf to) |
|---|
| 613 | 586 | { |
|---|
| 614 | 587 | struct pt_regs *regs = task_regs(target); |
|---|
| 615 | | - compat_ulong_t *k = kbuf; |
|---|
| 616 | | - compat_ulong_t __user *u = ubuf; |
|---|
| 617 | | - compat_ulong_t reg; |
|---|
| 588 | + unsigned int pos; |
|---|
| 618 | 589 | |
|---|
| 619 | | - pos /= sizeof(reg); |
|---|
| 620 | | - count /= sizeof(reg); |
|---|
| 590 | + for (pos = 0; pos < ELF_NGREG; pos++) |
|---|
| 591 | + membuf_store(&to, (compat_ulong_t)get_reg(regs, pos)); |
|---|
| 621 | 592 | |
|---|
| 622 | | - if (kbuf) |
|---|
| 623 | | - for (; count > 0 && pos < ELF_NGREG; --count) |
|---|
| 624 | | - *k++ = get_reg(regs, pos++); |
|---|
| 625 | | - else |
|---|
| 626 | | - for (; count > 0 && pos < ELF_NGREG; --count) |
|---|
| 627 | | - if (__put_user((compat_ulong_t) get_reg(regs, pos++), u++)) |
|---|
| 628 | | - return -EFAULT; |
|---|
| 629 | | - |
|---|
| 630 | | - kbuf = k; |
|---|
| 631 | | - ubuf = u; |
|---|
| 632 | | - pos *= sizeof(reg); |
|---|
| 633 | | - count *= sizeof(reg); |
|---|
| 634 | | - return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
|---|
| 635 | | - ELF_NGREG * sizeof(reg), -1); |
|---|
| 593 | + return 0; |
|---|
| 636 | 594 | } |
|---|
| 637 | 595 | |
|---|
| 638 | 596 | static int gpr32_set(struct task_struct *target, |
|---|
| .. | .. |
|---|
| 673 | 631 | [REGSET_GENERAL] = { |
|---|
| 674 | 632 | .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, |
|---|
| 675 | 633 | .size = sizeof(compat_long_t), .align = sizeof(compat_long_t), |
|---|
| 676 | | - .get = gpr32_get, .set = gpr32_set |
|---|
| 634 | + .regset_get = gpr32_get, .set = gpr32_set |
|---|
| 677 | 635 | }, |
|---|
| 678 | 636 | [REGSET_FP] = { |
|---|
| 679 | 637 | .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, |
|---|
| 680 | 638 | .size = sizeof(__u64), .align = sizeof(__u64), |
|---|
| 681 | | - .get = fpr_get, .set = fpr_set |
|---|
| 639 | + .regset_get = fpr_get, .set = fpr_set |
|---|
| 682 | 640 | } |
|---|
| 683 | 641 | }; |
|---|
| 684 | 642 | |
|---|
| .. | .. |
|---|
| 798 | 756 | return roff->name; |
|---|
| 799 | 757 | return NULL; |
|---|
| 800 | 758 | } |
|---|
| 759 | + |
|---|
| 760 | +/** |
|---|
| 761 | + * regs_within_kernel_stack() - check the address in the stack |
|---|
| 762 | + * @regs: pt_regs which contains kernel stack pointer. |
|---|
| 763 | + * @addr: address which is checked. |
|---|
| 764 | + * |
|---|
| 765 | + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). |
|---|
| 766 | + * If @addr is within the kernel stack, it returns true. If not, returns false. |
|---|
| 767 | + */ |
|---|
| 768 | +int regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) |
|---|
| 769 | +{ |
|---|
| 770 | + return ((addr & ~(THREAD_SIZE - 1)) == |
|---|
| 771 | + (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); |
|---|
| 772 | +} |
|---|
| 773 | + |
|---|
| 774 | +/** |
|---|
| 775 | + * regs_get_kernel_stack_nth() - get Nth entry of the stack |
|---|
| 776 | + * @regs: pt_regs which contains kernel stack pointer. |
|---|
| 777 | + * @n: stack entry number. |
|---|
| 778 | + * |
|---|
| 779 | + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which |
|---|
| 780 | + * is specified by @regs. If the @n th entry is NOT in the kernel stack, |
|---|
| 781 | + * this returns 0. |
|---|
| 782 | + */ |
|---|
| 783 | +unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) |
|---|
| 784 | +{ |
|---|
| 785 | + unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); |
|---|
| 786 | + |
|---|
| 787 | + addr -= n; |
|---|
| 788 | + |
|---|
| 789 | + if (!regs_within_kernel_stack(regs, (unsigned long)addr)) |
|---|
| 790 | + return 0; |
|---|
| 791 | + |
|---|
| 792 | + return *addr; |
|---|
| 793 | +} |
|---|