* [PATCH v2 0/2] ptrace_set_syscall_info: add support for seccomp syscall skipping
@ 2026-07-04 14:26 Renzo Davoli
2026-07-04 14:26 ` [PATCH v2 1/2] ptrace: PTRACE_SET_SYSCALL_INFO syscall skipping support Renzo Davoli
2026-07-04 14:26 ` [PATCH v2 2/2] selftests/ptrace: add a test case for PTRACE_SYSCALL_INFO syscall skipping Renzo Davoli
0 siblings, 2 replies; 6+ messages in thread
From: Renzo Davoli @ 2026-07-04 14:26 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
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 tracing a system call the tracer can get the system call information
in a portable manner using the ptrace tag PTRACE_GET_SYSCALL_INFO.
The op returned in struct ptrace_syscall_info can be
PTRACE_SYSCALL_INFO_ENTRY or PTRACE_SYSCALL_INFO_SECCOMP depending on
the way the system call was "captured".
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.
Patch 1/5 introduces adds a new feature to solve the problem.
When the tracer retrieves a ptrace_syscall_info structure with op ==
PTRACE_SYSCALL_INFO_SECCOMP or PTRACE_SYSCALL_INFO_ENTRY, it may choose to skip
the system call by changing op to PTRACE_SYSCALL_INFO_EXIT and populating the
exit union fields (rval and is_error) to define the return value and error
status for the tracee.
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 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: PTRACE_SET_SYSCALL_INFO syscall skipping support
selftests/ptrace: add a test case for PTRACE_SYSCALL_INFO syscall
skipping
kernel/ptrace.c | 28 ++-
.../selftests/ptrace/set_syscall_info.c | 176 +++++++++++++++++-
2 files changed, 198 insertions(+), 6 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/2] ptrace: PTRACE_SET_SYSCALL_INFO syscall skipping support
2026-07-04 14:26 [PATCH v2 0/2] ptrace_set_syscall_info: add support for seccomp syscall skipping Renzo Davoli
@ 2026-07-04 14:26 ` Renzo Davoli
2026-07-05 6:41 ` Renzo Davoli
2026-07-04 14:26 ` [PATCH v2 2/2] selftests/ptrace: add a test case for PTRACE_SYSCALL_INFO syscall skipping Renzo Davoli
1 sibling, 1 reply; 6+ messages in thread
From: Renzo Davoli @ 2026-07-04 14:26 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
This patch extends PTRACE_SET_SYSCALL_INFO with support for skipping a system
call triggered via seccomp.
When the tracer retrieves a ptrace_syscall_info structure with op ==
PTRACE_SYSCALL_INFO_SECCOMP or PTRACE_SYSCALL_INFO_ENTRY, it may choose to skip
the system call by changing op to PTRACE_SYSCALL_INFO_EXIT and populating the
exit union fields (rval and is_error) to define the return value and error
status for the tracee.
Signed-off-by: Renzo Davoli <renzo@cs.unibo.it>
---
kernel/ptrace.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index d041645d9d17..a77143dec5bd 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 child_op;
+ bool skip_syscall = false;
if (user_size < sizeof(info))
return -EINVAL;
@@ -1141,15 +1146,28 @@ 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 or PTRACE_SYSCALL_INFO_ENTRY can be changed
+ * to PTRACE_SYSCALL_INFO_EXIT to skip the system call
+ */
+
+ child_op = ptrace_get_syscall_info_op(child);
+ if (child_op != info.op) {
+ if (info.op == PTRACE_SYSCALL_INFO_EXIT &&
+ (child_op == PTRACE_SYSCALL_INFO_ENTRY ||
+ child_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.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 2/2] selftests/ptrace: add a test case for PTRACE_SYSCALL_INFO syscall skipping
2026-07-04 14:26 [PATCH v2 0/2] ptrace_set_syscall_info: add support for seccomp syscall skipping Renzo Davoli
2026-07-04 14:26 ` [PATCH v2 1/2] ptrace: PTRACE_SET_SYSCALL_INFO syscall skipping support Renzo Davoli
@ 2026-07-04 14:26 ` Renzo Davoli
1 sibling, 0 replies; 6+ messages in thread
From: Renzo Davoli @ 2026-07-04 14:26 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
Check whether PTRACE_SYSCALL_INFO syscall skiping semantics implemented in the
kernel matches userspace expectations.
Signed-off-by: Renzo Davoli <renzo@cs.unibo.it>
---
.../selftests/ptrace/set_syscall_info.c | 176 +++++++++++++++++-
1 file changed, 175 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..bcc867b627cd 100644
--- a/tools/testing/selftests/ptrace/set_syscall_info.c
+++ b/tools/testing/selftests/ptrace/set_syscall_info.c
@@ -11,9 +11,16 @@
#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 +43,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 +72,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 +155,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 +164,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 +543,151 @@ 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");
+ _exit(1);
+ }
+ ASSERT_EQ(0, sys_seccomp(SECCOMP_SET_MODE_FILTER, 0,
+ (void *) &seccomp_prog)) {
+ TH_LOG("seccomp: %m");
+ _exit(1);
+ }
+
+ /* run getpid unmodified */
+ ASSERT_EQ(tracee_pid, getpid()) {
+ TH_LOG("getpid seccomp unchanged: %m");
+ _exit(1);
+ }
+
+ /* run getppid instead of getpid */
+ ASSERT_EQ(tracer_pid, getpid()) {
+ TH_LOG("getpid seccomp nr changes: %m");
+ _exit(1);
+ }
+
+ /* skip getpid and return 42 */
+ ASSERT_EQ(42, getpid()) {
+ TH_LOG("getpid skip set return value changes: %m");
+ _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");
+ }
+
+ while (1) {
+ 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);
+ }
+
+ if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) {
+ struct ptrace_syscall_info info;
+ 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");
+ }
+
+ switch (ptrace_stop) {
+ case 0: ASSERT_EQ(__NR_getpid, info.seccomp.nr) {
+ LOG_KILL_TRACEE("step %d nr __NR_getpid mismatch: %m", ptrace_stop);
+ }
+ ptrace_stop++;
+ break;
+ case 1: ASSERT_EQ(__NR_getpid, info.seccomp.nr) {
+ LOG_KILL_TRACEE("step %d nr __NR_getpid mismatch: %m", ptrace_stop);
+ }
+ info.seccomp.nr = __NR_getppid;
+ ptrace_stop++;
+ break;
+ case 2: ASSERT_EQ(__NR_getpid, info.seccomp.nr) {
+ LOG_KILL_TRACEE("step %d nr __NR_getpid mismatch: %m", ptrace_stop);
+ }
+ info.op = PTRACE_SYSCALL_INFO_EXIT;
+ info.exit.rval = 42;
+ info.exit.is_error = 0;
+ ptrace_stop++;
+ break;
+ case 3: ASSERT_EQ(__NR_exit_group, info.seccomp.nr) {
+ LOG_KILL_TRACEE("step %d nr __NR_exit_group mismatch: %m", ptrace_stop);
+ }
+ break;
+ default:
+ LOG_KILL_TRACEE("unexpected system call: %m");
+ 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");
+ }
+ } else {
+ LOG_KILL_TRACEE("unexpected signal: %m");
+ }
+ }
+}
+
TEST_HARNESS_MAIN
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] ptrace: PTRACE_SET_SYSCALL_INFO syscall skipping support
2026-07-04 14:26 ` [PATCH v2 1/2] ptrace: PTRACE_SET_SYSCALL_INFO syscall skipping support Renzo Davoli
@ 2026-07-05 6:41 ` Renzo Davoli
2026-07-05 14:38 ` Oleg Nesterov
2026-07-06 16:03 ` Dmitry V. Levin
0 siblings, 2 replies; 6+ messages in thread
From: Renzo Davoli @ 2026-07-05 6:41 UTC (permalink / raw)
To: linux-kernel
Cc: Andrew Morton, Oleg Nesterov, Shuah Khan, Alexey Gladkov,
Eugene Syromyatnikov, Davide Berardi, strace-devel,
Dmitry V . Levin
There is a problem on MIPS:
https://sashiko.dev/#/patchset/20260704142643.692754-1-renzo%40cs.unibo.it
It appears that on MIPS the feature of skipping a system call by setting its
number to -1 does not work correctly when transitioning from _ENTRY to _EXIT:
the system call return value is overwritten.
PTRACE_EVENT_SECCOMP, however, has an explicit UAPI specification stating that
setting the system call number to a negative value suppresses the system call.
Moreover, kernel/ptrace.c contains the following comment:
/*
* If the syscall number is set to -1, setting syscall arguments is not
* just pointless, it would also clobber the syscall return value on
* those architectures that share the same register both for the first
* argument of syscall and its return value.
*/
Thus, PTRACE_EVENT_SECCOMP is explicitly designed to preserve the system call
return value when the system call is skipped.
By contrast, for PTRACE_SYSCALL syscall-entry stops, the man page only states
that the tracer may modify the system call number. It does not specify that
assigning a negative value must suppress the system call and preserve the
return value across all architectures, even though many architectures implement
exactly this behavior.
At this point I see two possible approaches:
* fix the MIPS implementation (and audit, and possibly fix, the other
architectures as well);
* revert to the original proposal and allow the "skip syscall" feature only for
PTRACE_EVENT_SECCOMP, i.e. permit PTRACE_SET_SYSCALL_INFO to transform only
PTRACE_SYSCALL_INFO_SECCOMP stops into PTRACE_SYSCALL_INFO_EXIT stops.
I would prefer the latter approach. I am concerned that changing the ptrace
implementation in each architecture may introduce subtle regressions or other
unintended side effects.
In my opinion, seccomp-based syscall tracing is also the more powerful and
flexible model compared to the traditional PTRACE_SYSCALL entry/exit mechanism.
Support for system call suppression from PTRACE_SYSCALL_INFO_ENTRY can always
be added later if and when a real use case arises. That would also provide an
opportunity to audit the behavior of all supported architectures and, if
necessary, make the semantics of negative system call numbers consistent across
architectures.
renzo
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] ptrace: PTRACE_SET_SYSCALL_INFO syscall skipping support
2026-07-05 6:41 ` Renzo Davoli
@ 2026-07-05 14:38 ` Oleg Nesterov
2026-07-06 16:03 ` Dmitry V. Levin
1 sibling, 0 replies; 6+ messages in thread
From: Oleg Nesterov @ 2026-07-05 14:38 UTC (permalink / raw)
To: Renzo Davoli, Thomas Bogendoerfer
Cc: linux-kernel, Andrew Morton, Shuah Khan, Alexey Gladkov,
Eugene Syromyatnikov, Davide Berardi, strace-devel,
Dmitry V . Levin, open list:MIPS
Oh... I know nothing about mips.
Add Thomas. Thomas could you help? See the question below.
OK, lets only allow the _SECCOMP -> _EXIT transition for now.
But will it work on MIPS?
grep, grep... So arch/mips/ has
static inline void syscall_set_return_value(struct task_struct *task,
struct pt_regs *regs,
int error, long val)
{
if (error) {
regs->regs[2] = -error;
regs->regs[7] = 1;
} else {
regs->regs[2] = val;
regs->regs[7] = 0;
}
}
static inline void syscall_set_nr(struct task_struct *task,
struct pt_regs *regs,
int nr)
{
/*
* New syscall number has to be assigned to regs[2] because
* it is loaded from there unconditionally after return from
* syscall_trace_enter() invocation.
*
* Consequently, if the syscall was indirect and nr != __NR_syscall,
* then after this assignment the syscall will cease to be indirect.
*/
task_thread_info(task)->syscall = regs->regs[2] = nr;
}
I have no idea. But at least ptrace_set_syscall_info_exit(skip => true)
must do syscall_set_nr(-1) before syscall_set_return_value(), otherwise
the value assigned to regs[2] will be lost.
-------------------------------------------------------------------------------
Now the question. To simplify, suppose we need something like
void skip_syscall_and_set_return_value(task, regs, retval)
{
syscall_set_nr(task, regs, -1);
syscall_set_return_value(task, regs, 0, retval);
}
which can be used by debugger when the tracee sleeps in ptrace_report_syscall_entry().
However, arch/mips/kernel/ptrace.c:syscall_trace_enter() does:
ptrace_report_syscall_entry(regs);
if (current_thread_info()->syscall < 0)
syscall_set_return_value(current, regs, -ENOSYS, 0);
and this means that this func won't work on MIPS. Is it possible to make it
work somehow? May be we can abuse regs->regs[7] somehow to detect the case when
syscall_set_return_value() was called by debugger and avoid the unconditional
-ENOSYS ?
Oleg.
On 07/05, Renzo Davoli wrote:
>
> There is a problem on MIPS:
> https://sashiko.dev/#/patchset/20260704142643.692754-1-renzo%40cs.unibo.it
>
> It appears that on MIPS the feature of skipping a system call by setting its
> number to -1 does not work correctly when transitioning from _ENTRY to _EXIT:
> the system call return value is overwritten.
>
> PTRACE_EVENT_SECCOMP, however, has an explicit UAPI specification stating that
> setting the system call number to a negative value suppresses the system call.
>
> Moreover, kernel/ptrace.c contains the following comment:
> /*
> * If the syscall number is set to -1, setting syscall arguments is not
> * just pointless, it would also clobber the syscall return value on
> * those architectures that share the same register both for the first
> * argument of syscall and its return value.
> */
> Thus, PTRACE_EVENT_SECCOMP is explicitly designed to preserve the system call
> return value when the system call is skipped.
>
> By contrast, for PTRACE_SYSCALL syscall-entry stops, the man page only states
> that the tracer may modify the system call number. It does not specify that
> assigning a negative value must suppress the system call and preserve the
> return value across all architectures, even though many architectures implement
> exactly this behavior.
>
> At this point I see two possible approaches:
>
> * fix the MIPS implementation (and audit, and possibly fix, the other
> architectures as well);
>
> * revert to the original proposal and allow the "skip syscall" feature only for
> PTRACE_EVENT_SECCOMP, i.e. permit PTRACE_SET_SYSCALL_INFO to transform only
> PTRACE_SYSCALL_INFO_SECCOMP stops into PTRACE_SYSCALL_INFO_EXIT stops.
>
> I would prefer the latter approach. I am concerned that changing the ptrace
> implementation in each architecture may introduce subtle regressions or other
> unintended side effects.
>
> In my opinion, seccomp-based syscall tracing is also the more powerful and
> flexible model compared to the traditional PTRACE_SYSCALL entry/exit mechanism.
>
> Support for system call suppression from PTRACE_SYSCALL_INFO_ENTRY can always
> be added later if and when a real use case arises. That would also provide an
> opportunity to audit the behavior of all supported architectures and, if
> necessary, make the semantics of negative system call numbers consistent across
> architectures.
>
> renzo
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] ptrace: PTRACE_SET_SYSCALL_INFO syscall skipping support
2026-07-05 6:41 ` Renzo Davoli
2026-07-05 14:38 ` Oleg Nesterov
@ 2026-07-06 16:03 ` Dmitry V. Levin
1 sibling, 0 replies; 6+ messages in thread
From: Dmitry V. Levin @ 2026-07-06 16:03 UTC (permalink / raw)
To: Renzo Davoli
Cc: linux-kernel, Andrew Morton, Oleg Nesterov, Shuah Khan,
Alexey Gladkov, Eugene Syromyatnikov, Davide Berardi,
strace-devel
On Sun, Jul 05, 2026 at 08:41:07AM +0200, Renzo Davoli wrote:
[...]
> Moreover, kernel/ptrace.c contains the following comment:
> /*
> * If the syscall number is set to -1, setting syscall arguments is not
> * just pointless, it would also clobber the syscall return value on
> * those architectures that share the same register both for the first
> * argument of syscall and its return value.
> */
I wrote this comment to warn explicitly against invoking
syscall_set_arguments() after syscall_set_nr(-1). Doing so is unsafe on
several architectures, as setting the first syscall argument will clobber
the syscall return value on those platforms.
[...]
> By contrast, for PTRACE_SYSCALL syscall-entry stops, the man page only states
> that the tracer may modify the system call number. It does not specify that
> assigning a negative value must suppress the system call and preserve the
> return value across all architectures, even though many architectures implement
> exactly this behavior.
While setting the system call number to an invalid value during a
syscall-entry stop indeed suppresses the system call on all architectures,
the return value semantics are complicated.
The return value is normally set to -ENOSYS, but there are architectures
(parisc between commits v4.6-rc2~20^2 and v5.0-rc8~9^2~1, and riscv
since commit v6.5-rc7~13^2~5) where -ENOSYS isn't set. Furthermore,
setting the return value along with the system call number during
a syscall-entry stop is not guaranteed to be honored on all architectures,
with MIPS being a notable example.
The man page could definitely be improved in this respect.
--
ldv
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-07-06 16:03 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-04 14:26 [PATCH v2 0/2] ptrace_set_syscall_info: add support for seccomp syscall skipping Renzo Davoli
2026-07-04 14:26 ` [PATCH v2 1/2] ptrace: PTRACE_SET_SYSCALL_INFO syscall skipping support Renzo Davoli
2026-07-05 6:41 ` Renzo Davoli
2026-07-05 14:38 ` Oleg Nesterov
2026-07-06 16:03 ` Dmitry V. Levin
2026-07-04 14:26 ` [PATCH v2 2/2] selftests/ptrace: add a test case for PTRACE_SYSCALL_INFO syscall skipping Renzo Davoli
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox