diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index fe2f2c595fd9..4139644030fb 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -159,6 +159,7 @@ config PPC select EDAC_SUPPORT select EDAC_ATOMIC_SCRUB select ARCH_HAS_DMA_SET_COHERENT_MASK + select HAVE_ARCH_SECCOMP_FILTER config GENERIC_CSUM def_bool CPU_LITTLE_ENDIAN diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 7484221bb3f8..737c0d0b53ac 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1762,6 +1762,44 @@ long arch_ptrace(struct task_struct *child, long request, return ret; } +#ifdef CONFIG_SECCOMP +static int do_seccomp(struct pt_regs *regs) +{ + if (!test_thread_flag(TIF_SECCOMP)) + return 0; + + /* + * The ABI we present to seccomp tracers is that r3 contains + * the syscall return value and orig_gpr3 contains the first + * syscall parameter. This is different to the ptrace ABI where + * both r3 and orig_gpr3 contain the first syscall parameter. + */ + regs->gpr[3] = -ENOSYS; + + /* + * We use the __ version here because we have already checked + * TIF_SECCOMP. If this fails, there is nothing left to do, we + * have already loaded -ENOSYS into r3, or seccomp has put + * something else in r3 (via SECCOMP_RET_ERRNO/TRACE). + */ + if (__secure_computing()) + return -1; + + /* + * The syscall was allowed by seccomp, restore the register + * state to what ptrace and audit expect. + * Note that we use orig_gpr3, which means a seccomp tracer can + * modify the first syscall parameter (in orig_gpr3) and also + * allow the syscall to proceed. + */ + regs->gpr[3] = regs->orig_gpr3; + + return 0; +} +#else +static inline int do_seccomp(struct pt_regs *regs) { return 0; } +#endif /* CONFIG_SECCOMP */ + /** * do_syscall_trace_enter() - Do syscall tracing on kernel entry. * @regs: the pt_regs of the task to trace (current) @@ -1787,7 +1825,8 @@ long do_syscall_trace_enter(struct pt_regs *regs) user_exit(); - secure_computing_strict(regs->gpr[0]); + if (do_seccomp(regs)) + return -1; if (test_thread_flag(TIF_SYSCALL_TRACE)) { /*