.. | .. |
---|
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 | +} |
---|