[PATCH 1/5] ptrace: add PTRACE_SYSCALL_INFO_SECCOMP_SKIP

Oleg Nesterov oleg at redhat.com
Thu Jul 2 09:58:14 UTC 2026


On 07/02, Renzo Davoli wrote:
>
> Hi Oleg,
>
> > Rather than add the new PTRACE_SYSCALL_INFO_SECCOMP_SKIP, can't we teach
> > ptrace_set_syscall_info_seccomp() to treat info->entry.nr == -1 as "skip" ?
> it already does
> > Note that ptrace_set_syscall_info_seccomp() -> ptrace_set_syscall_info_entry()
> > already does syscall_set_nr().
> Syscall skipping is useless if there is not a way to set the return value/errno.
>
> As I explain in the cover letter
> + 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.
>
> currently retvalue/errno can be set only at PTRACE_SYSCALL_INFO_EXIT

I meant something like below. This way both PTRACE_SYSCALL_INFO_ENTRY and
__SECCOMP can skip the syscall and set the return/errr value.

Oleg.
---


diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h
index 5f8ef6156752..4ee7870f3291 100644
--- a/include/uapi/linux/ptrace.h
+++ b/include/uapi/linux/ptrace.h
@@ -90,7 +90,13 @@ struct ptrace_syscall_info {
 	union {
 		struct {
 			__u64 nr;
-			__u64 args[6];
+			union {
+				__u64 args[6];
+				struct {
+					__s64 rval;
+					__u8 is_error;
+				};
+			};
 		} entry;
 		struct {
 			__s64 rval;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 130043bfc209..1daac0e62cfa 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -1031,6 +1031,28 @@ ptrace_get_syscall_info(struct task_struct *child, unsigned long user_size,
 	return copy_to_user(datavp, &info, write_size) ? -EFAULT : actual_size;
 }
 
+static int
+__set_syscall_info_exit(struct task_struct *child, struct pt_regs *regs,
+			__s64 __rval, __u8 __is_error)
+{
+	long rval = __rval;
+
+	/*
+	 * Check that the return value specified in info->exit.rval
+	 * is either a value of type "long" or a sign-extended value
+	 * of type "long".
+	 */
+	if (rval != __rval)
+		return -ERANGE;
+
+	if (__is_error)
+		syscall_set_return_value(child, regs, rval, 0);
+	else
+		syscall_set_return_value(child, regs, 0, rval);
+
+	return 0;
+}
+
 static int
 ptrace_set_syscall_info_entry(struct task_struct *child, struct pt_regs *regs,
 			      struct ptrace_syscall_info *info)
@@ -1047,6 +1069,11 @@ ptrace_set_syscall_info_entry(struct task_struct *child, struct pt_regs *regs,
 	if (nr != info->entry.nr)
 		return -ERANGE;
 
+	syscall_set_nr(child, regs, nr);
+	if (nr == -1)
+		return __set_syscall_info_exit(child, regs,
+						info->entry.rval, info->entry.is_error);
+
 	for (i = 0; i < ARRAY_SIZE(args); i++) {
 		args[i] = info->entry.args[i];
 		/*
@@ -1058,16 +1085,7 @@ ptrace_set_syscall_info_entry(struct task_struct *child, struct pt_regs *regs,
 			return -ERANGE;
 	}
 
-	syscall_set_nr(child, regs, nr);
-	/*
-	 * 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.
-	 */
-	if (nr != -1)
-		syscall_set_arguments(child, regs, args);
-
+	syscall_set_arguments(child, regs, args);
 	return 0;
 }
 
@@ -1086,22 +1104,8 @@ static int
 ptrace_set_syscall_info_exit(struct task_struct *child, struct pt_regs *regs,
 			     struct ptrace_syscall_info *info)
 {
-	long rval = info->exit.rval;
-
-	/*
-	 * Check that the return value specified in info->exit.rval
-	 * is either a value of type "long" or a sign-extended value
-	 * of type "long".
-	 */
-	if (rval != info->exit.rval)
-		return -ERANGE;
-
-	if (info->exit.is_error)
-		syscall_set_return_value(child, regs, rval, 0);
-	else
-		syscall_set_return_value(child, regs, 0, rval);
-
-	return 0;
+	return __set_syscall_info_exit(child, regs,
+		info->exit.rval, info->exit.is_error);
 }
 
 static int



More information about the Strace-devel mailing list