From: Yu Luming <luming...@gmail.com> Due to the common layer and internal calls details are hidden from the top level at the call side in ppc arch code, there are some difficulties in preserving all semantics implications of the original code in the patch. e.g when we got -1 returned from syscall_enter_from_user_mode, without touching common code, we have to do our own inference to recover the reasonable route to return, in order to have correct errno and syscall work behaviors,that are tested in seccomp_bpf 98 test cases.
Signed-off-by: Luming Yu <luming...@shingroup.cn> --- arch/powerpc/kernel/interrupt.c | 4 ++++ arch/powerpc/kernel/syscall.c | 28 +++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/interrupt.c b/arch/powerpc/kernel/interrupt.c index 2a5693b5f336..380697e35d3a 100644 --- a/arch/powerpc/kernel/interrupt.c +++ b/arch/powerpc/kernel/interrupt.c @@ -232,6 +232,7 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3, { unsigned long ti_flags; unsigned long ret = 0; + unsigned long work = READ_ONCE(current_thread_info()->syscall_work); bool is_not_scv = !IS_ENABLED(CONFIG_PPC_BOOK3S_64) || !scv; CT_WARN_ON(ct_state() == CT_STATE_USER); @@ -268,6 +269,9 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3, if (ti_flags & _TIF_SIGPENDING) ret |= _TIF_RESTOREALL; + + if (work) + ret |= _TIF_RESTOREALL; #ifdef CONFIG_PPC64 regs->exit_result = ret; #endif diff --git a/arch/powerpc/kernel/syscall.c b/arch/powerpc/kernel/syscall.c index dabe7f2b4bd4..358340f7fe75 100644 --- a/arch/powerpc/kernel/syscall.c +++ b/arch/powerpc/kernel/syscall.c @@ -18,6 +18,7 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0) { long ret; syscall_fn f; + unsigned long work = READ_ONCE(current_thread_info()->syscall_work); kuap_lock(); @@ -119,7 +120,7 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0) local_irq_enable(); - if (unlikely(read_thread_flags() & _TIF_SYSCALL_DOTRACE)) { + if (work & SYSCALL_WORK_ENTER) { if (unlikely(trap_is_unsupported_scv(regs))) { /* Unsupported scv vector */ _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); @@ -132,7 +133,32 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0) * and the test against NR_syscalls will fail and the return * value to be used is in regs->gpr[3]. */ + if (test_syscall_work(SECCOMP) && + !test_syscall_work(SYSCALL_EMU)) + regs->gpr[3] = -ENOSYS; r0 = syscall_enter_from_user_mode(regs, r0); + + if (test_syscall_work(SECCOMP)) { + if (r0 != -1) + regs->gpr[3] = regs->orig_gpr3; + else + goto skip; + } + if ((r0 == -1) && (test_syscall_work(SYSCALL_TRACE))) { + goto skip1; + } + if ((r0 == -1) && test_syscall_work(SYSCALL_EMU)) + goto skip; + if (regs->gpr[0] >= NR_syscalls) + goto skip1; + + r0 = regs->gpr[0]; + if (r0 != -1) + goto skip; +skip1: + r0 = -1; + regs->gpr[3] = -ENOSYS; +skip: if (unlikely(r0 >= NR_syscalls)) return regs->gpr[3]; -- 2.42.0.windows.2