From nobody Sat Sep 26 18:55:09 2026 Received: from mail.virtlab.unibo.it (mail.virtlab.unibo.it [130.136.161.50]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 131EE2F0661 for ; Mon, 31 Aug 2026 11:30:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=130.136.161.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788175824; cv=none; b=Vd8fhZXzh1ciAy8j4HHZUCFfNxgk/6e3Ij//o0Vk38I9FbXDJyurHz8dRyuGSq04LGdd84uUy7j1YcNPsAY9NwbnEbEOvBSQzInaY2xoHvWK2r3cRNey9zxpDVXghcnTZOgcO6B6qtFwJOF6289ZfGCI3J+Fr1YXZT+LKORTz1U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788175824; c=relaxed/simple; bh=iYYSxDNR1S58UTAcWamCyKcYlcoS5npcSZBlyQ6L+cY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bJo7uG2/r5Q6qGZjO3jla9PQkJSKC7RxkQkDRS3fYTBs4Hae6bviaZf//7iNmdd3Feb4Llav1bXJuMxCXRchXbj+B9Wcb/pjB5Q5YAuxcTNbPGVGTgkKOwBQAcVQCdsIU8XIwm/o4p3n2+tm8SfnpRHwUXylZM6uz5ZnauhDc1Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cs.unibo.it; spf=pass smtp.mailfrom=cs.unibo.it; dkim=pass (1024-bit key) header.d=cs.unibo.it header.i=@cs.unibo.it header.b=krNRTM9k; arc=none smtp.client-ip=130.136.161.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cs.unibo.it Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cs.unibo.it Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=cs.unibo.it header.i=@cs.unibo.it header.b="krNRTM9k" Received: from eipi10.cs.unibo.it (unknown [94.32.99.206]) by mail.virtlab.unibo.it (Postfix) with ESMTPA id A36981C0257; Mon, 31 Aug 2026 13:30:20 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=cs.unibo.it; s=virtlab; t=1788175820; bh=iYYSxDNR1S58UTAcWamCyKcYlcoS5npcSZBlyQ6L+cY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=krNRTM9kgPzAyOGUs2Z37IJ4hF4ESJLDxi08mnlynzRNfKFfjlU8XDdq8lcAWU655 owq9hJDM5ARNYrhgd11u9lof0YvluWBxrDb57ni3sVm5FLOtlxy+lIuQsVwngsX5t2 Ry/n/AgNmxnIXlrQbc5H1nEUo6e1mAN1NjexFKwI= From: Renzo Davoli To: linux-kernel@vger.kernel.org Cc: Renzo Davoli , Andrew Morton , Oleg Nesterov , Shuah Khan , Alexey Gladkov , Eugene Syromyatnikov , Davide Berardi , strace-devel@lists.strace.io, "Dmitry V . Levin" , Thomas Bogendoerfer Subject: [PATCH v3 1/3] asm/ptrace.h: add instruction_pointer_set Date: Mon, 31 Aug 2026 13:30:02 +0200 Message-ID: <20260831113004.259991-2-renzo@cs.unibo.it> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260831113004.259991-1-renzo@cs.unibo.it> References: <20260831113004.259991-1-renzo@cs.unibo.it> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add an instruction_pointer_set function for architectures that do not currently provide one. Signed-off-by: Renzo Davoli --- arch/alpha/include/asm/ptrace.h | 6 ++++++ arch/hexagon/include/asm/ptrace.h | 6 ++++++ arch/m68k/include/asm/ptrace.h | 6 ++++++ arch/microblaze/include/asm/ptrace.h | 6 ++++++ arch/nios2/include/asm/ptrace.h | 6 ++++++ arch/um/include/asm/ptrace-generic.h | 6 ++++++ arch/xtensa/include/asm/ptrace.h | 6 ++++++ 7 files changed, 42 insertions(+) diff --git a/arch/alpha/include/asm/ptrace.h b/arch/alpha/include/asm/ptrac= e.h index 8e0a589e2d15..a8cc325c4704 100644 --- a/arch/alpha/include/asm/ptrace.h +++ b/arch/alpha/include/asm/ptrace.h @@ -31,4 +31,10 @@ static inline unsigned long user_stack_pointer(struct pt= _regs *regs) return regs->usp; } =20 +static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + instruction_pointer(regs) =3D val; +} + #endif diff --git a/arch/hexagon/include/asm/ptrace.h b/arch/hexagon/include/asm/p= trace.h index ed35da1ee685..0a121f6e3bfc 100644 --- a/arch/hexagon/include/asm/ptrace.h +++ b/arch/hexagon/include/asm/ptrace.h @@ -18,6 +18,12 @@ extern const char *regs_query_register_name(unsigned int= offset); ((struct pt_regs *) \ ((unsigned long)current_thread_info() + THREAD_SIZE) - 1) =20 +static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + instruction_pointer(regs) =3D val; +} + #if CONFIG_HEXAGON_ARCH_VERSION >=3D 4 #define arch_has_single_step() (1) #endif diff --git a/arch/m68k/include/asm/ptrace.h b/arch/m68k/include/asm/ptrace.h index bc86ce012025..6e8a8f0daee8 100644 --- a/arch/m68k/include/asm/ptrace.h +++ b/arch/m68k/include/asm/ptrace.h @@ -18,6 +18,12 @@ (struct pt_regs *)((char *)current_thread_info() + THREAD_SIZE) - 1 #define current_user_stack_pointer() rdusp() =20 +static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + instruction_pointer(regs) =3D val; +} + #define arch_has_single_step() (1) =20 #ifdef CONFIG_MMU diff --git a/arch/microblaze/include/asm/ptrace.h b/arch/microblaze/include= /asm/ptrace.h index 17982292a64f..69e10658d7a9 100644 --- a/arch/microblaze/include/asm/ptrace.h +++ b/arch/microblaze/include/asm/ptrace.h @@ -20,5 +20,11 @@ static inline long regs_return_value(struct pt_regs *reg= s) return regs->r3; } =20 +static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + instruction_pointer(regs) =3D val; +} + #endif /* __ASSEMBLER__ */ #endif /* _ASM_MICROBLAZE_PTRACE_H */ diff --git a/arch/nios2/include/asm/ptrace.h b/arch/nios2/include/asm/ptrac= e.h index 96cbcd40c7ce..d120d8ecb187 100644 --- a/arch/nios2/include/asm/ptrace.h +++ b/arch/nios2/include/asm/ptrace.h @@ -70,6 +70,12 @@ struct switch_stack { #define user_stack_pointer(regs) ((regs)->sp) extern void show_regs(struct pt_regs *); =20 +static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + instruction_pointer(regs) =3D val; +} + #define current_pt_regs() \ ((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE)\ - 1) diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptr= ace-generic.h index 86d74f9d33cf..44beb96862d8 100644 --- a/arch/um/include/asm/ptrace-generic.h +++ b/arch/um/include/asm/ptrace-generic.h @@ -29,6 +29,12 @@ struct pt_regs { =20 #define PTRACE_OLDSETOPTIONS 21 =20 +static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + instruction_pointer(regs) =3D val; +} + struct task_struct; =20 extern long subarch_ptrace(struct task_struct *child, long request, diff --git a/arch/xtensa/include/asm/ptrace.h b/arch/xtensa/include/asm/ptr= ace.h index d0568ff6d349..97b14418955e 100644 --- a/arch/xtensa/include/asm/ptrace.h +++ b/arch/xtensa/include/asm/ptrace.h @@ -103,6 +103,12 @@ static inline unsigned long regs_return_value(struct p= t_regs *regs) return regs->areg[2]; } =20 +static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + instruction_pointer(regs) =3D val; +} + int do_syscall_trace_enter(struct pt_regs *regs); void do_syscall_trace_leave(struct pt_regs *regs); =20 --=20 2.55.0 From nobody Sat Sep 26 18:55:09 2026 Received: from mail.virtlab.unibo.it (mail.virtlab.unibo.it [130.136.161.50]) by smtp.subspace.kernel.org (Postfix) with ESMTP id BF1D9282F16 for ; Mon, 31 Aug 2026 11:30:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=130.136.161.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788175825; cv=none; b=USOley0tXXIM+4rXnSveavXDLMf60/wbSE+f4VIdM5aF0vv43IFkFJMLY8QaiQNSINdRv0gSa2VnC9Ju6Hw5krqfuC7Ghy/JeBHJDcXGSjEUvn+Q6pmwaM/RR/v0Q8tDIQpj3mvQ0oLjFFPX13pAJqUPmXAP7dL6VLVtA8tl9/U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788175825; c=relaxed/simple; bh=4ywa7uDPMt5wvv6eCmU4CDmJLUpEMNAeJ75LRTodfWg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=enFSRfgLS3wbO9A1HXprjizP7P6IQrUqgeAuBzmwcGJORFIHqGF065nYux2qP9A49s7MNTalDxgxdocOoCSCIJfqXRTysWTcJhTGzK1PIWOg+bgq5xKSY6msuOmSFkPXSpgtjVZX+Lpm3P4i0udQo6wLyrZBT4gKP1Eaa2445Uc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cs.unibo.it; spf=pass smtp.mailfrom=cs.unibo.it; dkim=pass (1024-bit key) header.d=cs.unibo.it header.i=@cs.unibo.it header.b=nEzlccRo; arc=none smtp.client-ip=130.136.161.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cs.unibo.it Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cs.unibo.it Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=cs.unibo.it header.i=@cs.unibo.it header.b="nEzlccRo" Received: from eipi10.cs.unibo.it (unknown [94.32.99.206]) by mail.virtlab.unibo.it (Postfix) with ESMTPA id B47C01C024E; Mon, 31 Aug 2026 13:30:21 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=cs.unibo.it; s=virtlab; t=1788175821; bh=4ywa7uDPMt5wvv6eCmU4CDmJLUpEMNAeJ75LRTodfWg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nEzlccRoHDGmkZ2JY7MAjUDbXxUEJEn6oiDIf4eZqXciik/8yWfr4NcKyEEiK7YCr vYyDuqOvsX6PVY8+9T3Qm2G5s6BdA4k6VFv79Ercm/NPZZ55d83l/wJTMZD0gzPLXZ QLOTh7yaMMQyVRUfNWyjAlNSIrbbLdGsX6AV2E1k= From: Renzo Davoli To: linux-kernel@vger.kernel.org Cc: Renzo Davoli , Andrew Morton , Oleg Nesterov , Shuah Khan , Alexey Gladkov , Eugene Syromyatnikov , Davide Berardi , strace-devel@lists.strace.io, "Dmitry V . Levin" , Thomas Bogendoerfer Subject: [PATCH v3 2/3] ptrace: add PTRACE_SYSCALL_INFO_FLAG_SET_IP Date: Mon, 31 Aug 2026 13:30:03 +0200 Message-ID: <20260831113004.259991-3-renzo@cs.unibo.it> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260831113004.259991-1-renzo@cs.unibo.it> References: <20260831113004.259991-1-renzo@cs.unibo.it> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. The proposal does not add any new ptrace capability. It merely provides a portable interface for a capability that already exists and is already reli= ed upon by existing applications. WHY PTRACE_SYSCALL_INFO_FLAG_SET_IP completes the set of actions that a tracer = can request when intercepting a system call. A tracer can currently instruct a tracee to: * execute the original system call; * execute a different system call (or the same system call with modified ar= guments); * skip the system call and provide the desired return value and/or errno. The proposed PTRACE_SYSCALL_INFO_FLAG_SET_IP adds a fourth possibility: * execute an arbitrary sequence of two or more system calls in place of the= original one. The mechanism is straightforward. During a PTRACE_SYSCALL_INFO_EXIT stop, t= he tracer rewinds the instruction pointer to the system call instruction (e.g.= by 2 bytes on x86-64 for syscall, or by the appropriate amount on other architectures). When the tracee resumes, it immediately generates a new syscall-entry stop, allowing the tracer to provide a new system call number= and arguments. By repeating this process, a tracer can transparently replace a single system call with any sequence of system calls. This capability already exists on all architectures through architecture-specific interfaces such as PTRACE_POKEUSER, PTRACE_SETREGS, or PTRACE_SETREGSET. PTRACE_SYSCALL_INFO_FLAG_SET_IP does not introduce a new capability; it merely exposes an existing one through the portable PTRACE_GET_SYSCALL_INFO/PTRACE_SET_SYSCALL_INFO API. WHO The VUOS project uses this mechanism extensively. VUOS provides namespace-like execution environments implemented entirely in user space, without relying on kernel namespaces. https://wiki.virtualsquare.org/#/tutorials/vuosbasics For example, VUOS allows unprivileged processes to use user-space implementations of filesystems (FUSE), networking stacks, virtual devices, = and other resources. To improve scalability on multicore systems, VUOS implements what we call t= he guardian angel model: each traced thread has its own dedicated tracer threa= d. This avoids a single tracer becoming a bottleneck. When a traced thread creates a child, ownership of the new tracee must be transferred to a newly created guardian angel. This requires delaying execu= tion of the child's first system call until the new tracer has attached. The current implementation proceeds as follows: * save the original system call number and arguments; * replace the system call with a blocking ppoll(NULL, 0, NULL, NULL) call; * detach the original tracer; * attach the new guardian angel using PTRACE_SEIZE; * interrupt the blocking ppoll() with PTRACE_INTERRUPT; * at the subsequent syscall-exit stop, rewind the instruction pointer to th= e system call instruction; * at the following syscall-entry stop, restore the original system call num= ber and arguments. This mechanism is currently implemented using architecture-specific register manipulation. PTRACE_SYSCALL_INFO_FLAG_SET_IP would allow the same implementation to be written using the portable ptrace syscall information = API. Although VUOS is the primary motivation for this proposal, the feature is generally useful for any project implementing ptrace-based system call interposition, including PRoot, strace's syscall injection machinery, and similar frameworks. Signed-off-by: Renzo Davoli --- 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 =20 +#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 64fd1b455297..6df38f139a2d 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -1130,6 +1130,7 @@ ptrace_set_syscall_info(struct task_struct *child, un= signed long user_size, struct ptrace_syscall_info info; int op; bool skip_syscall =3D false; + int ret; =20 if (user_size < sizeof(info)) return -EINVAL; @@ -1142,8 +1143,8 @@ ptrace_set_syscall_info(struct task_struct *child, un= signed long user_size, if (copy_from_user(&info, datavp, sizeof(info))) return -EFAULT; =20 - /* 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; =20 /* @@ -1164,15 +1165,29 @@ ptrace_set_syscall_info(struct task_struct *child, = unsigned long user_size, =20 switch (info.op) { case PTRACE_SYSCALL_INFO_ENTRY: - return ptrace_set_syscall_info_entry(child, regs, &info); + ret =3D 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 =3D 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 =3D ptrace_set_syscall_info_seccomp(child, regs, &info); + break; default: /* Other types of system call stops are not supported yet. */ return -EINVAL; } + + if (ret=3D=3D 0) { + if (info.flags & PTRACE_SYSCALL_INFO_FLAG_SET_IP) { + unsigned long ip =3D info.instruction_pointer; + if (ip !=3D info.instruction_pointer) + return -ERANGE; + instruction_pointer_set(regs, ip); + } + } + + return ret; } #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ =20 --=20 2.55.0 From nobody Sat Sep 26 18:55:09 2026 Received: from mail.virtlab.unibo.it (mail.virtlab.unibo.it [130.136.161.50]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 0F1483DA5AB for ; Mon, 31 Aug 2026 11:30:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=130.136.161.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788175827; cv=none; b=EwZcJDcIQtYE1MO8Q6EY3Y8BC6ZnE5RgWWqFEVSKgMhVN6uSKsv6jMmULRSQG5phFTwvV8vSilZ/1gskYVWizPCfXRM6MDt+S/VFSKtRSTXQgdNBPU4m71eHIxBPXv8ZhmYL45eWqdGWGio9I10VU8iyuuRO8vgcUi9NewsLgEw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788175827; c=relaxed/simple; bh=W9iD/bOfEqPrunYUCgVVM2rMwVFfUsJuX6F5x97mCws=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=K6n+UohC/8r+0+J39EXCsdS699qTTxppdXmpw8RjXNuqO7sHsini/bMrUYCMvGD0+q3r3189/P74ZQKWz01ofI5JTfsxV87RMX6c0Uk+5byLxbVbCJOhG4DNKSvHMTHnLxz5XOlLq0ZLR9jCrhHb1XPLaM7f2vKT/VNpEU+jdiw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cs.unibo.it; spf=pass smtp.mailfrom=cs.unibo.it; dkim=pass (1024-bit key) header.d=cs.unibo.it header.i=@cs.unibo.it header.b=x5kY3hJS; arc=none smtp.client-ip=130.136.161.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cs.unibo.it Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cs.unibo.it Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=cs.unibo.it header.i=@cs.unibo.it header.b="x5kY3hJS" Received: from eipi10.cs.unibo.it (unknown [94.32.99.206]) by mail.virtlab.unibo.it (Postfix) with ESMTPA id DEE8B1C025A; Mon, 31 Aug 2026 13:30:23 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=cs.unibo.it; s=virtlab; t=1788175824; bh=W9iD/bOfEqPrunYUCgVVM2rMwVFfUsJuX6F5x97mCws=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=x5kY3hJS9+M5Z7dT+YmVGPBN8svT5O4oinBaDINcVhxa2qDi5wcTtyqts8kYxfvyg AhuoAGKIy6LyOHijWUVQTlYwTvLqgfjx0bHdeqDIElP4IAntmBMXwbDzGrsoAtimFF OPVDxxtntXngQ5zYZKspZHzZazG8wLN2B//vuk9Q= From: Renzo Davoli To: linux-kernel@vger.kernel.org Cc: Renzo Davoli , Andrew Morton , Oleg Nesterov , Shuah Khan , Alexey Gladkov , Eugene Syromyatnikov , Davide Berardi , strace-devel@lists.strace.io, "Dmitry V . Levin" , Thomas Bogendoerfer Subject: [PATCH v3 3/3] selftests/ptrace: add a test case for PTRACE_SYSCALL_INFO_FLAG_SET_IP Date: Mon, 31 Aug 2026 13:30:04 +0200 Message-ID: <20260831113004.259991-4-renzo@cs.unibo.it> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260831113004.259991-1-renzo@cs.unibo.it> References: <20260831113004.259991-1-renzo@cs.unibo.it> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Check whether PTRACE_SYSCALL_INFO_FLAG_SET_IP semantics implemented in the kernel matches userspace expectations. Signed-off-by: Renzo Davoli --- .../selftests/ptrace/set_syscall_info.c | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/tools/testing/selftests/ptrace/set_syscall_info.c b/tools/test= ing/selftests/ptrace/set_syscall_info.c index cb2fe5295ae3..d7463fe4e011 100644 --- a/tools/testing/selftests/ptrace/set_syscall_info.c +++ b/tools/testing/selftests/ptrace/set_syscall_info.c @@ -90,6 +90,10 @@ static struct sock_fprog seccomp_prog =3D { .len =3D ARRAY_SIZE(seccomp_filter) }; =20 +static char w1[] =3D {'A', '\n'}; +static char w2[] =3D {'B', '\n'}; +static char w3[] =3D {'C', '\n'}; + static void check_psi_entry(struct __test_metadata *_metadata, const struct ptrace_syscall_info *info, @@ -698,4 +702,166 @@ TEST(set_syscall_info_seccomp) } } =20 +TEST(set_syscall_info_setip) +{ + tracer_pid =3D getpid(); + tracee_pid =3D fork(); + + ASSERT_LE(0, tracee_pid) { + TH_LOG("fork: %m"); + } + + /* tracee */ + if (tracee_pid =3D=3D 0) { + int rv; + + tracee_pid =3D 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); + } + +presyscall: + /* this sysall will run twice + (the tracer steps back the instruction pointer) */ + rv =3D write(1, w1, sizeof(w1)); + if (rv !=3D 2) { + _exit(1); + } + + /* run write unmodified */ + rv =3D write(1, w3, sizeof(w3)); + if (rv !=3D 2) { + _exit(1); + } + _exit(0); + } + + int status; + void *doitagain =3D &&presyscall; + + /* 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_TRACES= ECCOMP | 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[] =3D { + "unknown error", + "write unexpected return value", + "write unexpected set ip return value", + "final write unexpected set ip return value" + }; + + for (ptrace_stop =3D 0; ; ++ptrace_stop) { + ASSERT_EQ(tracee_pid, wait(&status)) { + /* cannot happen */ + LOG_KILL_TRACEE("wait: %m"); + } + if (WIFEXITED(status)) { + tracee_pid =3D 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 =3D 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_LT(ptrace_stop, ARRAY_SIZE(testname)) { + LOG_KILL_TRACEE("ptrace stop overflow"); + } + + if (status >> 8 =3D=3D (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) { + struct ptrace_syscall_info info; + size_t info_size =3D 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_FALSE(info.seccomp.nr =3D=3D __NR_exit_group && info.seccomp.arg= s[0] =3D=3D 1) { + LOG_KILL_TRACEE("tracee error: %s", + testname[ptrace_stop]); + } + + switch (ptrace_stop) { + case 0: + ASSERT_EQ(__NR_write, info.seccomp.nr) { + LOG_KILL_TRACEE("step %d nr __NR_write mismatch: %m", ptrace_stop); + } + info.instruction_pointer =3D (uintptr_t) doitagain; + info.flags =3D PTRACE_SYSCALL_INFO_FLAG_SET_IP; + break; + case 1: + info.seccomp.nr =3D __NR_write; + info.seccomp.args[0] =3D 1; + info.seccomp.args[1] =3D (uintptr_t) w2; + info.seccomp.args[2] =3D sizeof(w2); + break; + case 2: + ASSERT_EQ(__NR_write, info.seccomp.nr) { + LOG_KILL_TRACEE("step %d nr __NR_write mismatch: %m", 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_sto= p); + } + 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 --=20 2.55.0