[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