diff options
author | Matthew Leach <Matthew.Leach@arm.com> | 2013-11-28 07:07:22 -0500 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2013-11-28 13:01:28 -0500 |
commit | 6a2e5e521c333a0b56cb60dc5587e3f90859c5e7 (patch) | |
tree | 302469b5e34be7776fd899945f16d81eac2beb62 | |
parent | b3bf6aa7e79117419f7eddccf0b7af4382d823c3 (diff) |
arm64: ptrace: fix compat registes get/set to be endian clean
On a BE system the wrong half of the X registers is retrieved/written
when attempting to get/set the value of aarch32 registers through
ptrace.
Ensure that types are the correct width so that the relevant
casting occurs.
Signed-off-by: Matthew Leach <matthew.leach@arm.com>
Reviewed-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r-- | arch/arm64/kernel/ptrace.c | 40 |
1 files changed, 19 insertions, 21 deletions
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index fecdbf7de82e..6777a2192b83 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c | |||
@@ -636,28 +636,27 @@ static int compat_gpr_get(struct task_struct *target, | |||
636 | 636 | ||
637 | for (i = 0; i < num_regs; ++i) { | 637 | for (i = 0; i < num_regs; ++i) { |
638 | unsigned int idx = start + i; | 638 | unsigned int idx = start + i; |
639 | void *reg; | 639 | compat_ulong_t reg; |
640 | 640 | ||
641 | switch (idx) { | 641 | switch (idx) { |
642 | case 15: | 642 | case 15: |
643 | reg = (void *)&task_pt_regs(target)->pc; | 643 | reg = task_pt_regs(target)->pc; |
644 | break; | 644 | break; |
645 | case 16: | 645 | case 16: |
646 | reg = (void *)&task_pt_regs(target)->pstate; | 646 | reg = task_pt_regs(target)->pstate; |
647 | break; | 647 | break; |
648 | case 17: | 648 | case 17: |
649 | reg = (void *)&task_pt_regs(target)->orig_x0; | 649 | reg = task_pt_regs(target)->orig_x0; |
650 | break; | 650 | break; |
651 | default: | 651 | default: |
652 | reg = (void *)&task_pt_regs(target)->regs[idx]; | 652 | reg = task_pt_regs(target)->regs[idx]; |
653 | } | 653 | } |
654 | 654 | ||
655 | ret = copy_to_user(ubuf, reg, sizeof(compat_ulong_t)); | 655 | ret = copy_to_user(ubuf, ®, sizeof(reg)); |
656 | |||
657 | if (ret) | 656 | if (ret) |
658 | break; | 657 | break; |
659 | else | 658 | |
660 | ubuf += sizeof(compat_ulong_t); | 659 | ubuf += sizeof(reg); |
661 | } | 660 | } |
662 | 661 | ||
663 | return ret; | 662 | return ret; |
@@ -685,28 +684,28 @@ static int compat_gpr_set(struct task_struct *target, | |||
685 | 684 | ||
686 | for (i = 0; i < num_regs; ++i) { | 685 | for (i = 0; i < num_regs; ++i) { |
687 | unsigned int idx = start + i; | 686 | unsigned int idx = start + i; |
688 | void *reg; | 687 | compat_ulong_t reg; |
688 | |||
689 | ret = copy_from_user(®, ubuf, sizeof(reg)); | ||
690 | if (ret) | ||
691 | return ret; | ||
692 | |||
693 | ubuf += sizeof(reg); | ||
689 | 694 | ||
690 | switch (idx) { | 695 | switch (idx) { |
691 | case 15: | 696 | case 15: |
692 | reg = (void *)&newregs.pc; | 697 | newregs.pc = reg; |
693 | break; | 698 | break; |
694 | case 16: | 699 | case 16: |
695 | reg = (void *)&newregs.pstate; | 700 | newregs.pstate = reg; |
696 | break; | 701 | break; |
697 | case 17: | 702 | case 17: |
698 | reg = (void *)&newregs.orig_x0; | 703 | newregs.orig_x0 = reg; |
699 | break; | 704 | break; |
700 | default: | 705 | default: |
701 | reg = (void *)&newregs.regs[idx]; | 706 | newregs.regs[idx] = reg; |
702 | } | 707 | } |
703 | 708 | ||
704 | ret = copy_from_user(reg, ubuf, sizeof(compat_ulong_t)); | ||
705 | |||
706 | if (ret) | ||
707 | goto out; | ||
708 | else | ||
709 | ubuf += sizeof(compat_ulong_t); | ||
710 | } | 709 | } |
711 | 710 | ||
712 | if (valid_user_regs(&newregs.user_regs)) | 711 | if (valid_user_regs(&newregs.user_regs)) |
@@ -714,7 +713,6 @@ static int compat_gpr_set(struct task_struct *target, | |||
714 | else | 713 | else |
715 | ret = -EINVAL; | 714 | ret = -EINVAL; |
716 | 715 | ||
717 | out: | ||
718 | return ret; | 716 | return ret; |
719 | } | 717 | } |
720 | 718 | ||