From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 68C6460A263D for ; Tue, 20 Oct 2026 06:57:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key, unprotected) header.d=cs.unibo.it header.i=@cs.unibo.it header.a=rsa-sha256 header.s=virtlab header.b=oZeAzt9L Received: from boromir.ozlabs.org (localhost [127.0.0.1]) by lists.ozlabs.org (Postfix) with ESMTP id 4j83BH4gqKz30MY; Tue, 20 Oct 2026 17:57:11 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; arc=none smtp.remote-ip=130.136.161.50 ARC-Seal: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1792479431; cv=none; b=LtHD6ImbzteArlPVr6ZArSRdj9URen2EePEpADlEZtN5rzx++eedIkskKTUKHvxMTrgV+yVTDo8KFvAIITq/UzZNIf83VJ8zB67t+Mqa5V068wF/J98A3V0udoN2GJ8KzlY+K06eklIpZLTj08L9uMcuYKyQpV8yGJasxFUwP00S0jM+KvZ/Hiw38+Y2buQmtfNCtSGJ7y+3d2sdKdfDprlfS51RKbvBo3nBmIn1+oSnmCD9V0ztBght+7t+GunohhH8UqJDuTpOon2E/D5zorZxLEd0TWhzoHqrdcPtMMbXPFlqglkjSGNAMgpnMeFf7ZKfwu3B+SCBd6B4QvV0Gw== ARC-Message-Signature: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1792479431; c=relaxed/relaxed; bh=X7li7zppPfXAQDWIziNGfnEjMbFeJImmkhr9aLqumbs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=MAZ+LnBZE1dJv6XsQSJj36ZwJFBkIenmJJVCYYRQJuDjlLK/Hp8Z/PUYuMFf2sMvmbltaYXw/KQthAcyVjuV74N005sKDsaSFlHuPxPc/JjMNzXomq5+AFwQti4d4zIUAuE77W1ZOjW9wWAxbKY6/iC4SznMkPQTl/sYsw5lK+ZxN9K432eZQ1f2tyISZCfii9ootJVsCdEICC/m0teLyurSN+QSHM1wgFhOu18VkGMUcIOG0OX58FdqycwOTaOL7zeP4fnUA4FhwDYL8EJmEctqoIjDfH9Yzydy0spm3f8BnRwX/r/DORW3pVf5cfhU8E37DHGsimn39TKEZJx5Bg== ARC-Authentication-Results: i=1; lists.ozlabs.org; dmarc=pass (p=reject dis=none) header.from=cs.unibo.it; dkim=pass (1024-bit key; unprotected) header.d=cs.unibo.it header.i=@cs.unibo.it header.a=rsa-sha256 header.s=virtlab header.b=oZeAzt9L; dkim-atps=neutral; spf=pass (client-ip=130.136.161.50; helo=mail.virtlab.unibo.it; envelope-from=renzo@cs.unibo.it; receiver=lists.ozlabs.org) smtp.mailfrom=cs.unibo.it Authentication-Results: lists.ozlabs.org; dmarc=pass (p=reject dis=none) header.from=cs.unibo.it Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=cs.unibo.it header.i=@cs.unibo.it header.a=rsa-sha256 header.s=virtlab header.b=oZeAzt9L; dkim-atps=neutral Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=cs.unibo.it (client-ip=130.136.161.50; helo=mail.virtlab.unibo.it; envelope-from=renzo@cs.unibo.it; receiver=lists.ozlabs.org) Received: from mail.virtlab.unibo.it (mail.virtlab.unibo.it [130.136.161.50]) by lists.ozlabs.org (Postfix) with ESMTP id 4j83B970T7z2yql for ; Tue, 20 Oct 2026 17:57:03 +1100 (AEDT) Received: from eipi10.cs.unibo.it (unknown [94.32.99.206]) by mail.virtlab.unibo.it (Postfix) with ESMTPA id C28E71C0251; Tue, 20 Oct 2026 08:56:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=cs.unibo.it; s=virtlab; t=1792479420; bh=kecThFQauD5pORZjNAwNTrsBZzkWTRHw2R4hetODibc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oZeAzt9LAx7VhJ95rrODuBZq0TUfJxDYfDzhnRMVkLZgidLms+gqQ+yuahFM6mNtd yZ3NCF/HcuRHTW3fSXxGYOnTadPqNd85XyJ0IOCQOtrHlBi6e3Ns1YOMedfnBv8fZh VuaK6Hlki41GZHXsQheHgRRPKCNcY3ytcRhwl3+Y= From: Renzo Davoli To: linux-kernel@vger.kernel.org Cc: Davide Berardi , Oleg Nesterov , =?UTF-8?q?Michal=20Such=C3=A1nek?= , Kees Cook , Andy Lutomirski , Will Drewry , Thomas Gleixner , Andrew Morton , Shuah Khan , "Dmitry V . Levin" , Alexey Gladkov , Eugene Syromyatnikov , Thomas Bogendoerfer , Heiko Carstens , Vasily Gorbik , Madhavan Srinivasan , linuxppc-dev@lists.ozlabs.org, linux-s390@vger.kernel.org, linux-kselftest@vger.kernel.org, strace-devel@lists.strace.io, Renzo Davoli Subject: [PATCH v8 1/3] seccomp: let the tracer skip a syscall independently of its number Date: Tue, 20 Oct 2026 08:56:31 +0200 Message-ID: <20261020065635.490528-2-renzo@cs.unibo.it> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20261020065635.490528-1-renzo@cs.unibo.it> References: <20261020065635.490528-1-renzo@cs.unibo.it> X-Mailing-List: linuxppc-dev@lists.ozlabs.org List-Id: List-Help: List-Owner: List-Post: List-Archive: , List-Subscribe: , , Precedence: list X-Archived-By: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_PASS, SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=4.0.1 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on aws-us-west-2-korg-listserv-alma10-1 From: Davide Berardi At a PTRACE_EVENT_SECCOMP stop the tracer can only skip the system call by setting its number to -1, which seccomp reads back with syscall_get_nr(). This depends on how each architecture lays out the syscall number and the return value in the registers: - on some architectures the syscall number shares a register with the return value (e.g. v0 on MIPS), so setting the return value after the number would overwrite the skip request, and each of them needs its own way to keep it (MIPS keeps a copy of the number in thread_info); - on s390 syscall_get_nr() returns the low 16 bits of int_code, so -1 is read back as 65535: seccomp does not skip the call but runs the filters again on syscall 65535, which kills the task if the filter denies unknown syscalls. Add a per-task flag which the tracer sets with seccomp_ptrace_skip_syscall() while the tracee is stopped at the PTRACE_EVENT_SECCOMP stop, after it has set the return value. When the tracee resumes, seccomp skips the system call like for SECCOMP_RET_ERRNO, which every architecture already handles without touching the return value. The flag is cleared by the tracee before the stop and written by the tracer only while the tracee is stopped, so it needs no locking: the wake-up of the tracee orders it like the registers written by the tracer. The next patch uses this in PTRACE_SET_SYSCALL_INFO. Suggested-by: Michal Suchánek Assisted-by: claude-opus-5-5 Signed-off-by: Renzo Davoli --- include/linux/seccomp.h | 33 +++++++++++++++++++++++++++++++++ include/linux/seccomp_types.h | 4 ++++ kernel/seccomp.c | 11 ++++++++++- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index fcb3eb9825e5..ee31857f3ba6 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -75,6 +75,32 @@ static inline int seccomp_mode(struct seccomp *s) #ifdef CONFIG_SECCOMP_FILTER extern void seccomp_filter_release(struct task_struct *tsk); extern void get_seccomp_filter(struct task_struct *tsk); + +/** + * seccomp_ptrace_skip_syscall - make a tracee skip the current system call + * @tsk: tracee stopped at a PTRACE_EVENT_SECCOMP stop + * + * Must only be called by the tracer of @tsk while @tsk is stopped at a + * PTRACE_EVENT_SECCOMP stop, after it has set the return value of the system + * call. When the tracee resumes, the system call is skipped and the return + * value is left untouched, like with SECCOMP_RET_ERRNO. + */ +static inline void seccomp_ptrace_skip_syscall(struct task_struct *tsk) +{ + tsk->seccomp.ptrace_skip = true; +} + +/** + * seccomp_ptrace_syscall_skipped - check for seccomp_ptrace_skip_syscall() + * @tsk: tracee stopped at a PTRACE_EVENT_SECCOMP stop + * + * Return: true if the tracer requested to skip the system call during the + * current PTRACE_EVENT_SECCOMP stop of @tsk. + */ +static inline bool seccomp_ptrace_syscall_skipped(struct task_struct *tsk) +{ + return tsk->seccomp.ptrace_skip; +} #else /* CONFIG_SECCOMP_FILTER */ static inline void seccomp_filter_release(struct task_struct *tsk) { @@ -84,6 +110,13 @@ static inline void get_seccomp_filter(struct task_struct *tsk) { return; } +static inline void seccomp_ptrace_skip_syscall(struct task_struct *tsk) +{ +} +static inline bool seccomp_ptrace_syscall_skipped(struct task_struct *tsk) +{ + return false; +} #endif /* CONFIG_SECCOMP_FILTER */ #if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_CHECKPOINT_RESTORE) diff --git a/include/linux/seccomp_types.h b/include/linux/seccomp_types.h index cf0a0355024f..4bdb8424055b 100644 --- a/include/linux/seccomp_types.h +++ b/include/linux/seccomp_types.h @@ -18,11 +18,15 @@ struct seccomp_filter; * * @filter must only be accessed from the context of current as there * is no read locking. + * @ptrace_skip: set by the tracer while the task is stopped at a + * PTRACE_EVENT_SECCOMP stop to request that the system call is + * skipped, after it has set the return value. */ struct seccomp { int mode; atomic_t filter_count; struct seccomp_filter *filter; + bool ptrace_skip; }; #else diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 86cf4460d69e..edeb21fa3e23 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -1306,6 +1306,7 @@ static bool __seccomp_filter(int this_syscall, const bool recheck_after_trace) } /* Allow the BPF to provide the event message */ + current->seccomp.ptrace_skip = false; ptrace_event(PTRACE_EVENT_SECCOMP, data); /* * The delivery of a fatal signal during event @@ -1319,7 +1320,15 @@ static bool __seccomp_filter(int this_syscall, const bool recheck_after_trace) */ if (fatal_signal_pending(current)) goto skip; - /* Check if the tracer forced the syscall to be skipped. */ + /* + * Check if the tracer forced the syscall to be skipped, either + * with seccomp_ptrace_skip_syscall(), which does not depend on + * how the architecture encodes the syscall number and the + * return value in the registers, or by setting the syscall + * number to -1. + */ + if (current->seccomp.ptrace_skip) + goto skip; this_syscall = syscall_get_nr(current, current_pt_regs()); if (this_syscall < 0) goto skip; -- 2.55.0