aboutsummaryrefslogtreecommitdiff
path: root/arch/arm64/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/kernel/ptrace.c')
-rw-r--r--arch/arm64/kernel/ptrace.c48
1 files changed, 43 insertions, 5 deletions
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 167c5edecad4..50b26f12d63c 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -19,6 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/audit.h>
#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -26,6 +27,7 @@
#include <linux/smp.h>
#include <linux/ptrace.h>
#include <linux/user.h>
+#include <linux/seccomp.h>
#include <linux/security.h>
#include <linux/init.h>
#include <linux/signal.h>
@@ -39,6 +41,7 @@
#include <asm/compat.h>
#include <asm/debug-monitors.h>
#include <asm/pgtable.h>
+#include <asm/syscall.h>
#include <asm/traps.h>
#include <asm/system_misc.h>
@@ -1076,7 +1079,19 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data)
{
- return ptrace_request(child, request, addr, data);
+ int ret;
+
+ switch (request) {
+ case PTRACE_SET_SYSCALL:
+ task_pt_regs(child)->syscallno = data;
+ ret = 0;
+ break;
+ default:
+ ret = ptrace_request(child, request, addr, data);
+ break;
+ }
+
+ return ret;
}
enum ptrace_syscall_dir {
@@ -1108,19 +1123,42 @@ static void tracehook_report_syscall(struct pt_regs *regs,
asmlinkage int syscall_trace_enter(struct pt_regs *regs)
{
+ unsigned int saved_syscallno = regs->syscallno;
+
+ /* Do the secure computing check first; failures should be fast. */
+ if (secure_computing(regs->syscallno) == -1)
+ return RET_SKIP_SYSCALL_TRACE;
+
if (test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
- if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
- trace_sys_enter(regs, regs->syscallno);
+ if (IS_SKIP_SYSCALL(regs->syscallno)) {
+ /*
+ * RESTRICTION: we can't modify a return value of user
+ * issued syscall(-1) here. In order to ease this flavor,
+ * we need to treat whatever value in x0 as a return value,
+ * but this might result in a bogus value being returned.
+ */
+ /*
+ * NOTE: syscallno may also be set to -1 if fatal signal is
+ * detected in tracehook_report_syscall_entry(), but since
+ * a value set to x0 here is not used in this case, we may
+ * neglect the case.
+ */
+ if (!test_thread_flag(TIF_SYSCALL_TRACE) ||
+ (IS_SKIP_SYSCALL(saved_syscallno)))
+ regs->regs[0] = -ENOSYS;
+ }
+
+ audit_syscall_entry(syscall_get_arch(), regs->syscallno,
+ regs->orig_x0, regs->regs[1], regs->regs[2], regs->regs[3]);
return regs->syscallno;
}
asmlinkage void syscall_trace_exit(struct pt_regs *regs)
{
- if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
- trace_sys_exit(regs, regs_return_value(regs));
+ audit_syscall_exit(regs);
if (test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);