[PATCH v2 4/5] ptrace: add PTRACE_SYSCALL_INFO_FLAG_SET_IP

Renzo Davoli renzo at cs.unibo.it
Fri Jul 3 10:50:26 UTC 2026


This flag adds support for modifying the tracee's instruction pointer.

To do this, the tracer stores the new instruction pointer value in the
instruction_pointer field of the ptrace_syscall_info structure and
sets the PTRACE_SYSCALL_INFO_FLAG_SET_IP flag in the flags field.

This flag is introduced to avoid breaking existing code that uses
PTRACE_SET_SYSCALL_INFO and currently ignores the
instruction_pointer field.

Signed-off-by: Renzo Davoli <renzo at cs.unibo.it>
---
 include/uapi/linux/ptrace.h |  4 ++++
 kernel/ptrace.c             | 25 ++++++++++++++++++++-----
 2 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h
index 5f8ef6156752..6f62cb812875 100644
--- a/include/uapi/linux/ptrace.h
+++ b/include/uapi/linux/ptrace.h
@@ -80,6 +80,10 @@ struct seccomp_metadata {
 #define PTRACE_SYSCALL_INFO_EXIT	2
 #define PTRACE_SYSCALL_INFO_SECCOMP	3
 
+#define PTRACE_SYSCALL_INFO_FLAG_SET_IP (1 << 0)
+#define PTRACE_SYSCALL_INFO_FLAG_ALL \
+	(PTRACE_SYSCALL_INFO_FLAG_SET_IP)
+
 struct ptrace_syscall_info {
 	__u8 op;	/* PTRACE_SYSCALL_INFO_* */
 	__u8 reserved;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index a056f58fa82a..41bedc82a45c 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -1129,6 +1129,7 @@ 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;
 	bool skip_syscall;
+	int ret;
 
 	if (user_size < sizeof(info))
 		return -EINVAL;
@@ -1141,8 +1142,8 @@ ptrace_set_syscall_info(struct task_struct *child, unsigned long user_size,
 	if (copy_from_user(&info, datavp, sizeof(info)))
 		return -EFAULT;
 
-	/* Reserved for future use. */
-	if (info.flags || info.reserved)
+	/* Unused flags and fields reserved for future use. */
+	if ((info.flags & ~PTRACE_SYSCALL_INFO_FLAG_ALL) || info.reserved)
 		return -EINVAL;
 
 	/*
@@ -1160,15 +1161,29 @@ ptrace_set_syscall_info(struct task_struct *child, unsigned long user_size,
 
 	switch (info.op) {
 	case PTRACE_SYSCALL_INFO_ENTRY:
-		return ptrace_set_syscall_info_entry(child, regs, &info);
+		ret = ptrace_set_syscall_info_entry(child, regs, &info);
+		break;
 	case PTRACE_SYSCALL_INFO_EXIT:
-		return ptrace_set_syscall_info_exit(child, regs, &info, skip_syscall);
+		ret = ptrace_set_syscall_info_exit(child, regs, &info, skip_syscall);
+		break;
 	case PTRACE_SYSCALL_INFO_SECCOMP:
-		return ptrace_set_syscall_info_seccomp(child, regs, &info);
+		ret = ptrace_set_syscall_info_seccomp(child, regs, &info);
+		break;
 	default:
 		/* Other types of system call stops are not supported yet. */
 		return -EINVAL;
 	}
+
+	if (ret== 0) {
+		if (info.flags & PTRACE_SYSCALL_INFO_FLAG_SET_IP) {
+			unsigned long ip = info.instruction_pointer;
+			if (ip != info.instruction_pointer)
+				return -ERANGE;
+			instruction_pointer_set(regs, ip);
+		}
+	}
+
+	return ret;
 }
 #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */
 
-- 
2.53.0



More information about the Strace-devel mailing list