diff options
author | AKASHI Takahiro <takahiro.akashi@linaro.org> | 2014-11-28 00:26:34 -0500 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2014-11-28 05:19:49 -0500 |
commit | 766a85d7bc5d7f1ddd6de28bdb844eae45ec63b0 (patch) | |
tree | 3445af3c028dbaae227fcd3f74d45b80da115b8a /arch/arm64/kernel | |
parent | 034edabe6cf1d0dea49d4c836ba128cec90fad04 (diff) |
arm64: ptrace: add NT_ARM_SYSTEM_CALL regset
This regeset is intended to be used to get and set a system call number
while tracing.
There was some discussion about possible approaches to do so:
(1) modify x8 register with ptrace(PTRACE_SETREGSET) indirectly,
and update regs->syscallno later on in syscall_trace_enter(), or
(2) define a dedicated regset for this purpose as on s390, or
(3) support ptrace(PTRACE_SET_SYSCALL) as on arch/arm
Thinking of the fact that user_pt_regs doesn't expose 'syscallno' to
tracer as well as that secure_computing() expects a changed syscall number,
especially case of -1, to be visible before this function returns in
syscall_trace_enter(), (1) doesn't work well.
We will take (2) since it looks much cleaner.
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm64/kernel')
-rw-r--r-- | arch/arm64/kernel/ptrace.c | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 8a4ae8e73213..f576781d8d3b 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c | |||
@@ -551,6 +551,32 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset, | |||
551 | return ret; | 551 | return ret; |
552 | } | 552 | } |
553 | 553 | ||
554 | static int system_call_get(struct task_struct *target, | ||
555 | const struct user_regset *regset, | ||
556 | unsigned int pos, unsigned int count, | ||
557 | void *kbuf, void __user *ubuf) | ||
558 | { | ||
559 | int syscallno = task_pt_regs(target)->syscallno; | ||
560 | |||
561 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
562 | &syscallno, 0, -1); | ||
563 | } | ||
564 | |||
565 | static int system_call_set(struct task_struct *target, | ||
566 | const struct user_regset *regset, | ||
567 | unsigned int pos, unsigned int count, | ||
568 | const void *kbuf, const void __user *ubuf) | ||
569 | { | ||
570 | int syscallno, ret; | ||
571 | |||
572 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &syscallno, 0, -1); | ||
573 | if (ret) | ||
574 | return ret; | ||
575 | |||
576 | task_pt_regs(target)->syscallno = syscallno; | ||
577 | return ret; | ||
578 | } | ||
579 | |||
554 | enum aarch64_regset { | 580 | enum aarch64_regset { |
555 | REGSET_GPR, | 581 | REGSET_GPR, |
556 | REGSET_FPR, | 582 | REGSET_FPR, |
@@ -559,6 +585,7 @@ enum aarch64_regset { | |||
559 | REGSET_HW_BREAK, | 585 | REGSET_HW_BREAK, |
560 | REGSET_HW_WATCH, | 586 | REGSET_HW_WATCH, |
561 | #endif | 587 | #endif |
588 | REGSET_SYSTEM_CALL, | ||
562 | }; | 589 | }; |
563 | 590 | ||
564 | static const struct user_regset aarch64_regsets[] = { | 591 | static const struct user_regset aarch64_regsets[] = { |
@@ -608,6 +635,14 @@ static const struct user_regset aarch64_regsets[] = { | |||
608 | .set = hw_break_set, | 635 | .set = hw_break_set, |
609 | }, | 636 | }, |
610 | #endif | 637 | #endif |
638 | [REGSET_SYSTEM_CALL] = { | ||
639 | .core_note_type = NT_ARM_SYSTEM_CALL, | ||
640 | .n = 1, | ||
641 | .size = sizeof(int), | ||
642 | .align = sizeof(int), | ||
643 | .get = system_call_get, | ||
644 | .set = system_call_set, | ||
645 | }, | ||
611 | }; | 646 | }; |
612 | 647 | ||
613 | static const struct user_regset_view user_aarch64_view = { | 648 | static const struct user_regset_view user_aarch64_view = { |