* [PATCH v7 0/2] PTRACE_SET_SYSCALL_INFO: add support for seccomp syscall skipping
@ 2026-08-31 8:27 Renzo Davoli
2026-08-31 8:27 ` [PATCH v7 1/2] ptrace: add PTRACE_SET_SYSCALL_INFO syscall skipping support Renzo Davoli
2026-08-31 8:27 ` [PATCH v7 2/2] selftests/ptrace: add a test case for PTRACE_SET_SYSCALL_INFO syscall skipping Renzo Davoli
0 siblings, 2 replies; 5+ messages in thread
From: Renzo Davoli @ 2026-08-31 8:27 UTC (permalink / raw)
To: linux-kernel
Cc: Renzo Davoli, Andrew Morton, Oleg Nesterov, Shuah Khan,
Alexey Gladkov, Eugene Syromyatnikov, Davide Berardi,
strace-devel, Dmitry V . Levin, Thomas Bogendoerfer
PTRACE_SET_SYSCALL_INFO is a generic ptrace API that complements
PTRACE_GET_SYSCALL_INFO by allowing a tracer to modify details of a
system call in which the tracee is currently blocked.
The API is designed to let tracers inspect and modify system call
information in a simple, architecture-agnostic manner.
The current implementation only supports modifying the subset of
system call information needed by strace: the system call number,
arguments, and return value.
This patch set extends PTRACE_SET_SYSCALL_INFO with support for
skipping a system call.
When a seccomp filter returns SECCOMP_RET_TRACE, the tracer receives,
via PTRACE_GET_SYSCALL_INFO, a struct ptrace_syscall_info with
op == PTRACE_SYSCALL_INFO_SECCOMP.
The tracer can skip the system call by setting the system call number
to -1. However, the current PTRACE_SET_SYSCALL_INFO interface does not
provide a way to specify the return value or error code that should be
reported to the tracee after skipping the call.
This patchset extends PTRACE_SET_SYSCALL_INFO to support skipping a system call
triggered via seccomp.
When a tracer retrieves a ptrace_syscall_info structure with 'op' set to
PTRACE_SYSCALL_INFO_SECCOMP, it can now choose to skip the system call. To do
this, the tracer changes 'op' to PTRACE_SYSCALL_INFO_EXIT and populates the
exit union fields (rval and is_error) to define the return value and error
status for the tracee.
System call suppression via PTRACE_SYSCALL_INFO_ENTRY is currently not
implemented. On some architectures (e.g. MIPS), when a system call is
skipped by setting the syscall number to -1 at the entry stop, the
architecture entry path unconditionally overwrites the return value
register with -ENOSYS, clobbering any custom return value set by the
tracer at the entry stop.
This patchset is a new version of the proposed patchset entitled:
ptrace_set_syscall_info: add support for seccomp syscall skipping and
instruction pointer modification
The patchset has been split in two:
syscall skipping(this)
instruction pointer modification (it will be updated soon)
Changes in v7:
* rebased to Linux 7.3-rc1
Changes in v6:
* selftests/ptrace/set_syscall_info.c: improve messages in case of failure.
Changes in v5:
* reworded the explanation for not supporting PTRACE_SYSCALL_INFO_ENTRY yet.
* selftests/ptrace: removed a redundant check.
Changes in v4:
* Reworded the commit messages for clarity.
* Renamed the local variable child_op to op in ptrace_set_syscall_info()
* Clean up and improve the coding style of selftests/ptrace/set_syscall_info.c
(suggested by Dmitry V. Levin)
Changes in v3:
* restrict the syscall skipping feature to PTRACE_SYSCALL_INFO_SECCOMP
Changes in v2:
bugfix: _NONE -> _EXIT transition was erroneously permitted
Changes since the previous patchset v2:
* bugfix: skip_syscall init value
* fix comments
Changes in (previous patchset) v2:
* use PTRACE_SYSCALL_INFO_EXIT instead of a new tag
* fixed most of the comments from sashiko.dev
Renzo Davoli (2):
ptrace: add PTRACE_SET_SYSCALL_INFO syscall skipping support
selftests/ptrace: add a test case for PTRACE_SET_SYSCALL_INFO syscall
skipping
kernel/ptrace.c | 27 ++-
.../selftests/ptrace/set_syscall_info.c | 184 +++++++++++++++++-
2 files changed, 205 insertions(+), 6 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v7 1/2] ptrace: add PTRACE_SET_SYSCALL_INFO syscall skipping support 2026-08-31 8:27 [PATCH v7 0/2] PTRACE_SET_SYSCALL_INFO: add support for seccomp syscall skipping Renzo Davoli @ 2026-08-31 8:27 ` Renzo Davoli 2026-08-31 13:20 ` Oleg Nesterov 2026-08-31 8:27 ` [PATCH v7 2/2] selftests/ptrace: add a test case for PTRACE_SET_SYSCALL_INFO syscall skipping Renzo Davoli 1 sibling, 1 reply; 5+ messages in thread From: Renzo Davoli @ 2026-08-31 8:27 UTC (permalink / raw) To: linux-kernel Cc: Renzo Davoli, Andrew Morton, Oleg Nesterov, Shuah Khan, Alexey Gladkov, Eugene Syromyatnikov, Davide Berardi, strace-devel, Dmitry V . Levin, Thomas Bogendoerfer Extend PTRACE_SET_SYSCALL_INFO to support skipping a system call triggered via seccomp. When a tracer retrieves a ptrace_syscall_info structure with 'op' set to PTRACE_SYSCALL_INFO_SECCOMP, it can now choose to skip the system call. To do this, the tracer changes 'op' to PTRACE_SYSCALL_INFO_EXIT and populates the exit union fields (rval and is_error) to define the return value and error status for the tracee. System call suppression via PTRACE_SYSCALL_INFO_ENTRY is currently not implemented. On some architectures (e.g. MIPS), when a system call is skipped by setting the syscall number to -1 at the entry stop, the architecture entry path unconditionally overwrites the return value register with -ENOSYS, clobbering any custom return value set by the tracer at the entry stop. Signed-off-by: Renzo Davoli <renzo@cs.unibo.it> Reviewed-by: Oleg Nesterov <oleg@redhat.com> Reviewed-by: Dmitry V. Levin <ldv@strace.io> --- kernel/ptrace.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index d041645d9d17..64fd1b455297 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -1099,7 +1099,7 @@ ptrace_set_syscall_info_seccomp(struct task_struct *child, struct pt_regs *regs, static int ptrace_set_syscall_info_exit(struct task_struct *child, struct pt_regs *regs, - struct ptrace_syscall_info *info) + struct ptrace_syscall_info *info, bool skip_syscall) { long rval = info->exit.rval; @@ -1111,6 +1111,9 @@ ptrace_set_syscall_info_exit(struct task_struct *child, struct pt_regs *regs, if (rval != info->exit.rval) return -ERANGE; + if (skip_syscall) + syscall_set_nr(child, regs, -1); + if (info->exit.is_error) syscall_set_return_value(child, regs, rval, 0); else @@ -1125,6 +1128,8 @@ ptrace_set_syscall_info(struct task_struct *child, unsigned long user_size, { struct pt_regs *regs = task_pt_regs(child); struct ptrace_syscall_info info; + int op; + bool skip_syscall = false; if (user_size < sizeof(info)) return -EINVAL; @@ -1141,15 +1146,27 @@ ptrace_set_syscall_info(struct task_struct *child, unsigned long user_size, if (info.flags || info.reserved) return -EINVAL; - /* Changing the type of the system call stop is not supported yet. */ - if (ptrace_get_syscall_info_op(child) != info.op) - return -EINVAL; + /* + * Changing the type of the system call stop is not allowed, with the + * following exception: + * PTRACE_SYSCALL_INFO_SECCOMP can be changed to PTRACE_SYSCALL_INFO_EXIT + * to skip the system call + */ + + op = ptrace_get_syscall_info_op(child); + if (op != info.op) { + if (info.op == PTRACE_SYSCALL_INFO_EXIT && + op == PTRACE_SYSCALL_INFO_SECCOMP) + skip_syscall = true; + else + return -EINVAL; + } switch (info.op) { case PTRACE_SYSCALL_INFO_ENTRY: return ptrace_set_syscall_info_entry(child, regs, &info); case PTRACE_SYSCALL_INFO_EXIT: - return ptrace_set_syscall_info_exit(child, regs, &info); + return ptrace_set_syscall_info_exit(child, regs, &info, skip_syscall); case PTRACE_SYSCALL_INFO_SECCOMP: return ptrace_set_syscall_info_seccomp(child, regs, &info); default: -- 2.55.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v7 1/2] ptrace: add PTRACE_SET_SYSCALL_INFO syscall skipping support 2026-08-31 8:27 ` [PATCH v7 1/2] ptrace: add PTRACE_SET_SYSCALL_INFO syscall skipping support Renzo Davoli @ 2026-08-31 13:20 ` Oleg Nesterov 2026-08-31 13:43 ` Michal Suchánek 0 siblings, 1 reply; 5+ messages in thread From: Oleg Nesterov @ 2026-08-31 13:20 UTC (permalink / raw) To: Renzo Davoli, Michal Suchánek Cc: linux-kernel, Andrew Morton, Shuah Khan, Alexey Gladkov, Eugene Syromyatnikov, Davide Berardi, strace-devel, Dmitry V . Levin, Thomas Bogendoerfer Well, still looks good to me... But I forgot (sorry, actually didn't really read) the previous discussions and IIRC Michal had some concerns about this patch. And you don't CC him. Michal, can you take a look? Do you see anything wrong? Oleg. On 08/31, Renzo Davoli wrote: > > Extend PTRACE_SET_SYSCALL_INFO to support skipping a system call triggered > via seccomp. > > When a tracer retrieves a ptrace_syscall_info structure with 'op' set to > PTRACE_SYSCALL_INFO_SECCOMP, it can now choose to skip the system call. > To do this, the tracer changes 'op' to PTRACE_SYSCALL_INFO_EXIT and > populates the exit union fields (rval and is_error) to define the return > value and error status for the tracee. > > System call suppression via PTRACE_SYSCALL_INFO_ENTRY is currently not > implemented. On some architectures (e.g. MIPS), when a system call is > skipped by setting the syscall number to -1 at the entry stop, the > architecture entry path unconditionally overwrites the return value > register with -ENOSYS, clobbering any custom return value set by the > tracer at the entry stop. > > Signed-off-by: Renzo Davoli <renzo@cs.unibo.it> > Reviewed-by: Oleg Nesterov <oleg@redhat.com> > Reviewed-by: Dmitry V. Levin <ldv@strace.io> > --- > kernel/ptrace.c | 27 ++++++++++++++++++++++----- > 1 file changed, 22 insertions(+), 5 deletions(-) > > diff --git a/kernel/ptrace.c b/kernel/ptrace.c > index d041645d9d17..64fd1b455297 100644 > --- a/kernel/ptrace.c > +++ b/kernel/ptrace.c > @@ -1099,7 +1099,7 @@ ptrace_set_syscall_info_seccomp(struct task_struct *child, struct pt_regs *regs, > > static int > ptrace_set_syscall_info_exit(struct task_struct *child, struct pt_regs *regs, > - struct ptrace_syscall_info *info) > + struct ptrace_syscall_info *info, bool skip_syscall) > { > long rval = info->exit.rval; > > @@ -1111,6 +1111,9 @@ ptrace_set_syscall_info_exit(struct task_struct *child, struct pt_regs *regs, > if (rval != info->exit.rval) > return -ERANGE; > > + if (skip_syscall) > + syscall_set_nr(child, regs, -1); > + > if (info->exit.is_error) > syscall_set_return_value(child, regs, rval, 0); > else > @@ -1125,6 +1128,8 @@ ptrace_set_syscall_info(struct task_struct *child, unsigned long user_size, > { > struct pt_regs *regs = task_pt_regs(child); > struct ptrace_syscall_info info; > + int op; > + bool skip_syscall = false; > > if (user_size < sizeof(info)) > return -EINVAL; > @@ -1141,15 +1146,27 @@ ptrace_set_syscall_info(struct task_struct *child, unsigned long user_size, > if (info.flags || info.reserved) > return -EINVAL; > > - /* Changing the type of the system call stop is not supported yet. */ > - if (ptrace_get_syscall_info_op(child) != info.op) > - return -EINVAL; > + /* > + * Changing the type of the system call stop is not allowed, with the > + * following exception: > + * PTRACE_SYSCALL_INFO_SECCOMP can be changed to PTRACE_SYSCALL_INFO_EXIT > + * to skip the system call > + */ > + > + op = ptrace_get_syscall_info_op(child); > + if (op != info.op) { > + if (info.op == PTRACE_SYSCALL_INFO_EXIT && > + op == PTRACE_SYSCALL_INFO_SECCOMP) > + skip_syscall = true; > + else > + return -EINVAL; > + } > > switch (info.op) { > case PTRACE_SYSCALL_INFO_ENTRY: > return ptrace_set_syscall_info_entry(child, regs, &info); > case PTRACE_SYSCALL_INFO_EXIT: > - return ptrace_set_syscall_info_exit(child, regs, &info); > + return ptrace_set_syscall_info_exit(child, regs, &info, skip_syscall); > case PTRACE_SYSCALL_INFO_SECCOMP: > return ptrace_set_syscall_info_seccomp(child, regs, &info); > default: > -- > 2.55.0 > ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v7 1/2] ptrace: add PTRACE_SET_SYSCALL_INFO syscall skipping support 2026-08-31 13:20 ` Oleg Nesterov @ 2026-08-31 13:43 ` Michal Suchánek 0 siblings, 0 replies; 5+ messages in thread From: Michal Suchánek @ 2026-08-31 13:43 UTC (permalink / raw) To: Oleg Nesterov Cc: Renzo Davoli, linux-kernel, Andrew Morton, Shuah Khan, Alexey Gladkov, Eugene Syromyatnikov, Davide Berardi, strace-devel, Dmitry V . Levin, Thomas Bogendoerfer Hello, on some architectures the syscall return value overlaps with the syscall number or syscall arguments - see https://www.man7.org/linux/man-pages/man2/syscall.2.html When calling a seccomp filter the filter is able to return a value which then tells the kernel if the syscall state should be interpreted as entry (syscall nr + arguments) or exit (syscall skipped, registers have return value). ptrace has no way to return a value, and from the register state alone it is not possible to tell if the syscall state is entry or exit. Some architectures affected by this overlap problem implement an architecture-specific thread info flag that tells the kernel that the syscall is alreaady dispatched. However, this flag is architecture-specific, and you would need to set it in architecture independent code. You could make this flag architecture independent (and even set it to 0 on architectures that are not affected) which would then allow this to work in general. Otherwise this API is non-protable, and broken from the start. On Mon, Aug 31, 2026 at 03:20:15PM +0200, Oleg Nesterov wrote: > Well, still looks good to me... > > But I forgot (sorry, actually didn't really read) the previous discussions > and IIRC Michal had some concerns about this patch. And you don't CC him. > > Michal, can you take a look? Do you see anything wrong? > > Oleg. > > On 08/31, Renzo Davoli wrote: > > > > Extend PTRACE_SET_SYSCALL_INFO to support skipping a system call triggered > > via seccomp. > > > > When a tracer retrieves a ptrace_syscall_info structure with 'op' set to > > PTRACE_SYSCALL_INFO_SECCOMP, it can now choose to skip the system call. > > To do this, the tracer changes 'op' to PTRACE_SYSCALL_INFO_EXIT and > > populates the exit union fields (rval and is_error) to define the return > > value and error status for the tracee. > > > > System call suppression via PTRACE_SYSCALL_INFO_ENTRY is currently not > > implemented. On some architectures (e.g. MIPS), when a system call is > > skipped by setting the syscall number to -1 at the entry stop, the > > architecture entry path unconditionally overwrites the return value > > register with -ENOSYS, clobbering any custom return value set by the > > tracer at the entry stop. > > > > Signed-off-by: Renzo Davoli <renzo@cs.unibo.it> > > Reviewed-by: Oleg Nesterov <oleg@redhat.com> > > Reviewed-by: Dmitry V. Levin <ldv@strace.io> > > --- > > kernel/ptrace.c | 27 ++++++++++++++++++++++----- > > 1 file changed, 22 insertions(+), 5 deletions(-) > > > > diff --git a/kernel/ptrace.c b/kernel/ptrace.c > > index d041645d9d17..64fd1b455297 100644 > > --- a/kernel/ptrace.c > > +++ b/kernel/ptrace.c > > @@ -1099,7 +1099,7 @@ ptrace_set_syscall_info_seccomp(struct task_struct *child, struct pt_regs *regs, > > > > static int > > ptrace_set_syscall_info_exit(struct task_struct *child, struct pt_regs *regs, > > - struct ptrace_syscall_info *info) > > + struct ptrace_syscall_info *info, bool skip_syscall) > > { > > long rval = info->exit.rval; > > > > @@ -1111,6 +1111,9 @@ ptrace_set_syscall_info_exit(struct task_struct *child, struct pt_regs *regs, > > if (rval != info->exit.rval) > > return -ERANGE; > > > > + if (skip_syscall) > > + syscall_set_nr(child, regs, -1); > > + > > if (info->exit.is_error) > > syscall_set_return_value(child, regs, rval, 0); > > else > > @@ -1125,6 +1128,8 @@ ptrace_set_syscall_info(struct task_struct *child, unsigned long user_size, > > { > > struct pt_regs *regs = task_pt_regs(child); > > struct ptrace_syscall_info info; > > + int op; > > + bool skip_syscall = false; > > > > if (user_size < sizeof(info)) > > return -EINVAL; > > @@ -1141,15 +1146,27 @@ ptrace_set_syscall_info(struct task_struct *child, unsigned long user_size, > > if (info.flags || info.reserved) > > return -EINVAL; > > > > - /* Changing the type of the system call stop is not supported yet. */ > > - if (ptrace_get_syscall_info_op(child) != info.op) > > - return -EINVAL; > > + /* > > + * Changing the type of the system call stop is not allowed, with the > > + * following exception: > > + * PTRACE_SYSCALL_INFO_SECCOMP can be changed to PTRACE_SYSCALL_INFO_EXIT > > + * to skip the system call > > + */ > > + > > + op = ptrace_get_syscall_info_op(child); > > + if (op != info.op) { > > + if (info.op == PTRACE_SYSCALL_INFO_EXIT && > > + op == PTRACE_SYSCALL_INFO_SECCOMP) > > + skip_syscall = true; > > + else > > + return -EINVAL; > > + } > > > > switch (info.op) { > > case PTRACE_SYSCALL_INFO_ENTRY: > > return ptrace_set_syscall_info_entry(child, regs, &info); > > case PTRACE_SYSCALL_INFO_EXIT: > > - return ptrace_set_syscall_info_exit(child, regs, &info); > > + return ptrace_set_syscall_info_exit(child, regs, &info, skip_syscall); Here it might be preferable to define a new function that does the skip=true part and calls ptrace_set_syscall_info_exit. Looking at the code it would not be the first. Thanks Michal > > case PTRACE_SYSCALL_INFO_SECCOMP: > > return ptrace_set_syscall_info_seccomp(child, regs, &info); > > default: > > -- > > 2.55.0 > > > ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v7 2/2] selftests/ptrace: add a test case for PTRACE_SET_SYSCALL_INFO syscall skipping 2026-08-31 8:27 [PATCH v7 0/2] PTRACE_SET_SYSCALL_INFO: add support for seccomp syscall skipping Renzo Davoli 2026-08-31 8:27 ` [PATCH v7 1/2] ptrace: add PTRACE_SET_SYSCALL_INFO syscall skipping support Renzo Davoli @ 2026-08-31 8:27 ` Renzo Davoli 1 sibling, 0 replies; 5+ messages in thread From: Renzo Davoli @ 2026-08-31 8:27 UTC (permalink / raw) To: linux-kernel Cc: Renzo Davoli, Andrew Morton, Oleg Nesterov, Shuah Khan, Alexey Gladkov, Eugene Syromyatnikov, Davide Berardi, strace-devel, Dmitry V . Levin, Thomas Bogendoerfer Check whether PTRACE_SET_SYSCALL_INFO syscall skipping semantics implemented in the kernel matches userspace expectations. Signed-off-by: Renzo Davoli <renzo@cs.unibo.it> Reviewed-by: Dmitry V. Levin <ldv@strace.io> --- .../selftests/ptrace/set_syscall_info.c | 184 +++++++++++++++++- 1 file changed, 183 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/ptrace/set_syscall_info.c b/tools/testing/selftests/ptrace/set_syscall_info.c index 1cc411a41cd6..cb2fe5295ae3 100644 --- a/tools/testing/selftests/ptrace/set_syscall_info.c +++ b/tools/testing/selftests/ptrace/set_syscall_info.c @@ -11,9 +11,15 @@ #include <err.h> #include <fcntl.h> #include <signal.h> +#include <stdlib.h> +#include <stddef.h> #include <asm/unistd.h> +#include <sys/prctl.h> #include <linux/types.h> #include <linux/ptrace.h> +#include <linux/filter.h> +#include <linux/seccomp.h> +#include <linux/prctl.h> #if defined(_MIPS_SIM) && _MIPS_SIM == _MIPS_SIM_NABI32 /* @@ -36,6 +42,7 @@ struct si_exit { static unsigned int ptrace_stop; static pid_t tracee_pid; +static pid_t tracer_pid; static int kill_tracee(pid_t pid) @@ -64,6 +71,25 @@ sys_ptrace(int request, pid_t pid, unsigned long addr, unsigned long data) ptrace_stop, ##__VA_ARGS__); \ } while (0) +static int sys_seccomp(unsigned int operation, unsigned int flags, void *args) +{ + return syscall(__NR_seccomp, operation, flags, args); +} + +static struct sock_filter seccomp_filter[] = { + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)), + + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_restart_syscall, 0, 1), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), + + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRACE), +}; + +static struct sock_fprog seccomp_prog = { + .filter = seccomp_filter, + .len = ARRAY_SIZE(seccomp_filter) +}; + static void check_psi_entry(struct __test_metadata *_metadata, const struct ptrace_syscall_info *info, @@ -128,7 +154,6 @@ check_psi_exit(struct __test_metadata *_metadata, TEST(set_syscall_info) { - const pid_t tracer_pid = getpid(); const kernel_ulong_t dummy[] = { (kernel_ulong_t) 0xdad0bef0bad0fed0ULL, (kernel_ulong_t) 0xdad1bef1bad1fed1ULL, @@ -138,6 +163,7 @@ TEST(set_syscall_info) (kernel_ulong_t) 0xdad5bef5bad5fed5ULL, }; int splice_in[2], splice_out[2]; + tracer_pid = getpid(); ASSERT_EQ(0, pipe(splice_in)); ASSERT_EQ(0, pipe(splice_out)); @@ -516,4 +542,160 @@ TEST(set_syscall_info) ASSERT_EQ(ptrace_stop, ARRAY_SIZE(si) * 2); } +TEST(set_syscall_info_seccomp) +{ + tracer_pid = getpid(); + tracee_pid = fork(); + + ASSERT_LE(0, tracee_pid) { + TH_LOG("fork: %m"); + } + + /* tracee */ + if (tracee_pid == 0) { + tracee_pid = getpid(); + ASSERT_EQ(0, sys_ptrace(PTRACE_TRACEME, 0, 0, 0)) { + TH_LOG("PTRACE_TRACEME: %m"); + } + ASSERT_EQ(0, kill(tracee_pid, SIGSTOP)) { + /* cannot happen */ + TH_LOG("kill SIGSTOP: %m"); + } + + ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { + TH_LOG("prctl: %m"); + } + ASSERT_EQ(0, sys_seccomp(SECCOMP_SET_MODE_FILTER, 0, + (void *) &seccomp_prog)) { + TH_LOG("seccomp: %m"); + } + + /* run getpid unmodified */ + ASSERT_EQ(tracee_pid, getpid()) { + _exit(1); + } + + /* run getppid instead of getpid */ + ASSERT_EQ(tracer_pid, getpid()) { + _exit(1); + } + + /* skip getpid and return 42 */ + ASSERT_EQ(42, getpid()) { + _exit(1); + } + _exit(0); + } + + int status; + + /* tracer */ + ASSERT_LE(0, waitpid(-1, &status, 0)) { + LOG_KILL_TRACEE("waitpid: %m"); + } + + ASSERT_EQ(0, sys_ptrace(PTRACE_SETOPTIONS, tracee_pid, 0, + (PTRACE_O_TRACESECCOMP | PTRACE_O_TRACESYSGOOD))) + LOG_KILL_TRACEE("PTRACE_SETOPTIONS: %m"); + + ASSERT_EQ(0, sys_ptrace(PTRACE_CONT, tracee_pid, 0, 0)) { + LOG_KILL_TRACEE("PTRACE_CONT: %m"); + } + + const char *testname[] = { + "unknown error", + "getpid seccomp unchanged", + "getpid seccomp nr change: getppid", + "getpid seccomp skip+set retvalue" + }; + + const unsigned int expected_nr[] = { + __NR_getpid, + __NR_getpid, + __NR_getpid, + __NR_exit_group + }; + + for (ptrace_stop = 0; ; ++ptrace_stop) { + ASSERT_EQ(tracee_pid, wait(&status)) { + /* cannot happen */ + LOG_KILL_TRACEE("wait: %m"); + } + + if (WIFEXITED(status)) { + tracee_pid = 0; /* the tracee is no more */ + ASSERT_EQ(0, WEXITSTATUS(status)) { + LOG_KILL_TRACEE("unexpected exit status %u", + WEXITSTATUS(status)); + } + break; + } + ASSERT_FALSE(WIFSIGNALED(status)) { + tracee_pid = 0; /* the tracee is no more */ + LOG_KILL_TRACEE("unexpected signal %u", + WTERMSIG(status)); + } + ASSERT_TRUE(WIFSTOPPED(status)) { + LOG_KILL_TRACEE("unexpected wait status %#x", status); + } + + ASSERT_EQ(status >> 8, SIGTRAP | (PTRACE_EVENT_SECCOMP << 8)) { + LOG_KILL_TRACEE("unexpected stop, wait status %#x", status); + } + + struct ptrace_syscall_info info = { + .op = 0xff /* invalid PTRACE_SYSCALL_INFO_* op */ + }; + size_t info_size = sizeof(info); + + ASSERT_LT(0, sys_ptrace(PTRACE_GET_SYSCALL_INFO, tracee_pid, info_size, (uintptr_t) &info)) { + LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m"); + } + ASSERT_EQ(PTRACE_SYSCALL_INFO_SECCOMP, info.op) { + LOG_KILL_TRACEE("entry op mismatch: %m"); + } + ASSERT_TRUE(info.arch) { + LOG_KILL_TRACEE("entry arch mismatch: %m"); + } + ASSERT_TRUE(info.instruction_pointer) { + LOG_KILL_TRACEE("entry instruction_pointer mismatch: %m"); + } + ASSERT_TRUE(info.stack_pointer) { + LOG_KILL_TRACEE("entry stack_pointer mismatch: %m"); + } + + ASSERT_LT(ptrace_stop, ARRAY_SIZE(expected_nr)) { + LOG_KILL_TRACEE("ptrace stop overflow"); + } + ASSERT_FALSE(info.seccomp.nr == __NR_exit_group && info.seccomp.args[0] == 1) { + LOG_KILL_TRACEE("tracee error: %s", + testname[ptrace_stop]); + } + ASSERT_EQ(info.seccomp.nr, expected_nr[ptrace_stop]) { + LOG_KILL_TRACEE("syscall nr mismatch"); + } + switch (ptrace_stop) { + case 0: + case 3: + break; + case 1: + info.seccomp.nr = __NR_getppid; + break; + case 2: + info.op = PTRACE_SYSCALL_INFO_EXIT; + info.exit.rval = 42; + info.exit.is_error = 0; + break; + } + + ASSERT_EQ(0, sys_ptrace(PTRACE_SET_SYSCALL_INFO, tracee_pid, info_size, (uintptr_t) &info)) { + LOG_KILL_TRACEE("PTRACE_SET_SYSCALL_INFO: %m"); + } + + ASSERT_EQ(0, sys_ptrace(PTRACE_CONT, tracee_pid, 0, 0)) { + LOG_KILL_TRACEE("PTRACE_CONT: %m"); + } + } +} + TEST_HARNESS_MAIN -- 2.55.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-31 13:44 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-31 8:27 [PATCH v7 0/2] PTRACE_SET_SYSCALL_INFO: add support for seccomp syscall skipping Renzo Davoli 2026-08-31 8:27 ` [PATCH v7 1/2] ptrace: add PTRACE_SET_SYSCALL_INFO syscall skipping support Renzo Davoli 2026-08-31 13:20 ` Oleg Nesterov 2026-08-31 13:43 ` Michal Suchánek 2026-08-31 8:27 ` [PATCH v7 2/2] selftests/ptrace: add a test case for PTRACE_SET_SYSCALL_INFO syscall skipping Renzo Davoli
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.