ptrace: introduce PTRACE_SET_SYSCALL_INFO API
Subsystems (24)
v3 cover ptrace: introduce PTRACE_SET_SYSCALL_INFO API
PTRACE_SET_SYSCALL_INFO is a generic ptrace API that complements PTRACE_GET_SYSCALL_INFO by letting the ptracer modify details of system calls the tracee is blocked in.
This API allows ptracers to obtain and modify system call details in a straightforward and architecture-agnostic way.
Current implementation supports changing only those bits of system call information that are used by strace, namely, syscall number, syscall arguments, and syscall return value.
Support of changing additional details returned by PTRACE_GET_SYSCALL_INFO, such as instruction pointer and stack pointer, could be added later if needed, by using struct ptrace_syscall_info.flags to specify the additional details that should be set. Currently, "flags", "reserved", and "seccomp.reserved2" fields of struct ptrace_syscall_info must be initialized with zeroes; "arch", "instruction_pointer", and "stack_pointer" fields are ignored.
PTRACE_SET_SYSCALL_INFO currently supports only PTRACE_SYSCALL_INFO_ENTRY, PTRACE_SYSCALL_INFO_EXIT, and PTRACE_SYSCALL_INFO_SECCOMP operations. Other operations could be added later if needed.
Ideally, PTRACE_SET_SYSCALL_INFO should have been introduced along with PTRACE_GET_SYSCALL_INFO, but it didn't happen. The last straw that convinced me to implement PTRACE_SET_SYSCALL_INFO was apparent failure to provide an API of changing the first system call argument on riscv architecture [1].
ptrace(2) man page:
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
...PTRACE_SET_SYSCALL_INFO
Modify information about the system call that caused the stop. The "data" argument is a pointer to struct ptrace_syscall_info that specifies the system call information to be set.
The "addr" argument should be set to sizeof(struct ptrace_syscall_info)).
[1] https://lore.kernel.org/all/[email protected]/
Notes:
v3:
* powerpc: Submit syscall_set_return_value fix for "sc" case separately
* mips: Do not introduce erroneous argument truncation on mips n32, add a detailed description to the commit message of the mips_get_syscall_arg change
* ptrace: Add explicit padding to the end of struct ptrace_syscall_info, simplify obtaining of user ptrace_syscall_info,
do not introduce PTRACE_SYSCALL_INFO_SIZE_VER0
* ptrace: Change the return type of ptrace_set_syscall_info_* functions from "unsigned long" to "int"
* ptrace: Add -ERANGE check to ptrace_set_syscall_info_exit, add comments to -ERANGE checks
* ptrace: Update comments about supported syscall stops
* selftests: Extend set_syscall_info test, fix for mips n32
* Add Tested-by and Reviewed-by
v2:
* Add patch to fix syscall_set_return_value() on powerpc
* Add patch to fix mips_get_syscall_arg() on mips
* Add syscall_set_return_value() implementation on hexagon
* Add syscall_set_return_value() invocation to syscall_set_nr() on arm and arm64.
* Fix syscall_set_nr() and mips_set_syscall_arg() on mips
* Add a comment to syscall_set_nr() on arc, powerpc, s390, sh, and sparc
* Remove redundant ptrace_syscall_info.op assignments in ptrace_get_syscall_info_*
* Minor style tweaks in ptrace_get_syscall_info_op()
* Remove syscall_set_return_value() invocation from ptrace_set_syscall_info_entry()
* Skip syscall_set_arguments() invocation in case of syscall number -1 in ptrace_set_syscall_info_entry()
* Split ptrace_syscall_info.reserved into ptrace_syscall_info.reserved and ptrace_syscall_info.flags
* Use __kernel_ulong_t instead of unsigned long in set_syscall_info test
Dmitry V. Levin (6):
mips: fix mips_get_syscall_arg() for o32
syscall.h: add syscall_set_arguments() and syscall_set_return_value() syscall.h: introduce syscall_set_nr()
ptrace_get_syscall_info: factor out ptrace_get_syscall_info_op
ptrace: introduce PTRACE_SET_SYSCALL_INFO request selftests/ptrace: add a test case for PTRACE_SET_SYSCALL_INFO
arch/arc/include/asm/syscall.h | 25 + arch/arm/include/asm/syscall.h | 37 ++ arch/arm64/include/asm/syscall.h | 29 + arch/csky/include/asm/syscall.h | 13 + arch/hexagon/include/asm/syscall.h | 21 + arch/loongarch/include/asm/syscall.h | 15 + arch/m68k/include/asm/syscall.h | 7 + arch/microblaze/include/asm/syscall.h | 7 + arch/mips/include/asm/syscall.h | 70 ++- arch/nios2/include/asm/syscall.h | 16 + arch/openrisc/include/asm/syscall.h | 13 + arch/parisc/include/asm/syscall.h | 19 + arch/powerpc/include/asm/syscall.h | 20 + arch/riscv/include/asm/syscall.h | 16 + arch/s390/include/asm/syscall.h | 24 + arch/sh/include/asm/syscall_32.h | 24 + arch/sparc/include/asm/syscall.h | 22 + arch/um/include/asm/syscall-generic.h | 19 + arch/x86/include/asm/syscall.h | 43 ++ arch/xtensa/include/asm/syscall.h | 18 + include/asm-generic/syscall.h | 30 + include/uapi/linux/ptrace.h | 7 +- kernel/ptrace.c | 179 +++++- tools/testing/selftests/ptrace/Makefile | 2 +- .../selftests/ptrace/set_syscall_info.c | 514 ++++++++++++++++++ 25 files changed, 1143 insertions(+), 47 deletions(-) create mode 100644 tools/testing/selftests/ptrace/set_syscall_info.c
Signature · 1 line
ldv
PATCH v3 1/6 mips: fix mips_get_syscall_arg() for o32
This makes ptrace/get_syscall_info selftest pass on mips o32 and mips64 o32 by fixing the following two test assertions:
1. get_syscall_info test assertion on mips o32:
# get_syscall_info.c:218:get_syscall_info:Expected exp_args[5] (3134521044) == info.entry.args[4] (4911432) # get_syscall_info.c:219:get_syscall_info:wait #1: entry stop mismatch
2. get_syscall_info test assertion on mips64 o32:
# get_syscall_info.c:209:get_syscall_info:Expected exp_args[2] (3134324433) == info.entry.args[1] (18446744072548908753) # get_syscall_info.c:210:get_syscall_info:wait #1: entry stop mismatch
The first assertion is fixed for mips o32 by using struct pt_regs.pad0 instead of get_user() to obtain syscall arguments. This approach works due to this piece in arch/mips/kernel/scall32-o32.S:
/*
* Ok, copy the args from the luser stack to the kernel stack.
*/
.set push
.set noreorder
.set nomacro
load_a4: user_lw(t5, 16(t0)) # argument #5 from usp
load_a5: user_lw(t6, 20(t0)) # argument #6 from usp
load_a6: user_lw(t7, 24(t0)) # argument #7 from usp
load_a7: user_lw(t8, 28(t0)) # argument #8 from usp
loads_done:
sw t5, 16(sp) # argument #5 to ksp
sw t6, 20(sp) # argument #6 to ksp
sw t7, 24(sp) # argument #7 to ksp
sw t8, 28(sp) # argument #8 to ksp
.set pop
.section __ex_table,"a"
PTR_WD load_a4, bad_stack_a4
PTR_WD load_a5, bad_stack_a5
PTR_WD load_a6, bad_stack_a6
PTR_WD load_a7, bad_stack_a7
.previousarch/mips/kernel/scall64-o32.S has analogous code for mips64 o32 that allows obtaining syscall arguments from struct pt_regs.regs[4..11] instead of get_user().
The second assertion is fixed by truncating 64-bit values to 32-bit syscall arguments.
--- arch/mips/include/asm/syscall.h | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-)
arch/mips/include/asm/syscall.h +8 -24
@@ -57,37 +57,21 @@ static inline void mips_syscall_update_nr(struct task_struct *task,static inline void mips_get_syscall_arg (unsigned long *arg,struct task_struct *task,struct pt_regs *regs,unsigned int n) { -unsigned long usp__maybe_unused = regs->regs[29 ]; - +#ifdef CONFIG_32BIT switch (n) {case 0 :case 1 :case 2 :case 3 : *arg = regs->regs[4 + n]; - -return ; - -#ifdef CONFIG_32BIT -case 4 :case 5 :case 6 :case 7 : -get_user (*arg, (int *)usp + n);return ; -#endif - -#ifdef CONFIG_64BIT case 4 :case 5 :case 6 :case 7 : -#ifdef CONFIG_MIPS32_O32 -if (test_tsk_thread_flag (task,TIF_32BIT_REGS )) -get_user (*arg, (int *)usp + n); - else -#endif - *arg = regs->regs[4 + n]; - + *arg = regs->pad0[n];return ; -#endif - -default : -BUG (); } - -unreachable (); +#else + *arg = regs->regs[4 + n]; +if ((IS_ENABLED (CONFIG_MIPS32_O32 ) && +test_tsk_thread_flag (task,TIF_32BIT_REGS ))) + *arg = (unsigned int )*arg; +#endif } static inline long syscall_get_error(struct task_struct *task,
Signature · 1 line
ldv
PATCH v3 2/6 syscall.h: add syscall_set_arguments() and syscall_set_return_value()
In reply to Dmitry V. LevinThese functions are going to be needed on all HAVE_ARCH_TRACEHOOK architectures to implement PTRACE_SET_SYSCALL_INFO API.
This partially reverts commit 7962c2eddbfe ("arch: remove unused function syscall_set_arguments()") by reusing some of old syscall_set_arguments() implementations.
--- arch/arc/include/asm/syscall.h | 14 +++++++++++ arch/arm/include/asm/syscall.h | 13 ++++++++++ arch/arm64/include/asm/syscall.h | 13 ++++++++++ arch/csky/include/asm/syscall.h | 13 ++++++++++ arch/hexagon/include/asm/syscall.h | 14 +++++++++++ arch/loongarch/include/asm/syscall.h | 8 ++++++ arch/mips/include/asm/syscall.h | 32 ++++++++++++++++++++++++ arch/nios2/include/asm/syscall.h | 11 ++++++++ arch/openrisc/include/asm/syscall.h | 7 ++++++ arch/parisc/include/asm/syscall.h | 12 +++++++++ arch/powerpc/include/asm/syscall.h | 10 ++++++++ arch/riscv/include/asm/syscall.h | 9 +++++++ arch/s390/include/asm/syscall.h | 12 +++++++++ arch/sh/include/asm/syscall_32.h | 12 +++++++++ arch/sparc/include/asm/syscall.h | 10 ++++++++ arch/um/include/asm/syscall-generic.h | 14 +++++++++++ arch/x86/include/asm/syscall.h | 36 +++++++++++++++++++++++++++ arch/xtensa/include/asm/syscall.h | 11 ++++++++ include/asm-generic/syscall.h | 16 ++++++++++++ 19 files changed, 267 insertions(+)
arch/arc/include/asm/syscall.h +14 -0
@@ -67,6 +67,20 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, } } +static inline void +syscall_set_arguments (struct task_struct *task,struct pt_regs *regs, +unsigned long *args) +{ +unsigned long *inside_ptregs = ®s->r0; +unsigned int n =6 ; +unsigned int i =0 ; + +while (n--) { + *inside_ptregs = args[i++]; + inside_ptregs--; + } +} +static inline int syscall_get_arch (struct task_struct *task) {
arch/arm/include/asm/syscall.h +13 -0
@@ -80,6 +80,19 @@ static inline void syscall_get_arguments(struct task_struct *task,memcpy (args, ®s->ARM_r0 +1 ,5 *sizeof (args[0 ])); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +memcpy (®s->ARM_r0, args,6 *sizeof (args[0 ])); +/* +* Also copy the first argument into ARM_ORIG_r0 +* so that syscall_get_arguments() would return it +* instead of the previous value. +*/ + regs->ARM_ORIG_r0 = regs->ARM_r0; +} +static inline int syscall_get_arch (struct task_struct *task) {/* ARM tasks don't change audit architectures on the fly. */
arch/arm64/include/asm/syscall.h +13 -0
@@ -73,6 +73,19 @@ static inline void syscall_get_arguments(struct task_struct *task,memcpy (args, ®s->regs[1 ],5 *sizeof (args[0 ])); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +memcpy (®s->regs[0 ], args,6 *sizeof (args[0 ])); +/* +* Also copy the first argument into orig_x0 +* so that syscall_get_arguments() would return it +* instead of the previous value. +*/ + regs->orig_x0 = regs->regs[0 ]; +} +/* * We don't care about endianness (__AUDIT_ARCH_LE bit) here because * AArch64 has the same system calls both on little- and big- endian.
arch/csky/include/asm/syscall.h +13 -0
@@ -59,6 +59,19 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,memcpy (args, ®s->a1,5 *sizeof (args[0 ])); } +static inline void +syscall_set_arguments (struct task_struct *task,struct pt_regs *regs, +const unsigned long *args) +{ +memcpy (®s->a0, args,6 *sizeof (regs->a0)); +/* +* Also copy the first argument into orig_x0 +* so that syscall_get_arguments() would return it +* instead of the previous value. +*/ + regs->orig_a0 = regs->a0; +} +static inline int syscall_get_arch (struct task_struct *task) {
arch/hexagon/include/asm/syscall.h +14 -0
@@ -33,6 +33,13 @@ static inline void syscall_get_arguments(struct task_struct *task,memcpy (args, &(®s->r00)[0 ],6 *sizeof (args[0 ])); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +unsigned long *args) +{ +memcpy (&(®s->r00)[0 ], args,6 *sizeof (args[0 ])); +} +static inline long syscall_get_error (struct task_struct *task,struct pt_regs *regs) {
@@ -45,6 +52,13 @@ static inline long syscall_get_return_value(struct task_struct *task,return regs->r00; } +static inline void syscall_set_return_value (struct task_struct *task, +struct pt_regs *regs, +int error,long val) +{ + regs->r00 = (long ) error ?: val; +} +static inline int syscall_get_arch (struct task_struct *task) {return AUDIT_ARCH_HEXAGON ;
arch/loongarch/include/asm/syscall.h +8 -0
@@ -61,6 +61,14 @@ static inline void syscall_get_arguments(struct task_struct *task,memcpy (&args[1 ], ®s->regs[5 ],5 *sizeof (long )); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +unsigned long *args) +{ + regs->orig_a0 = args[0 ]; +memcpy (®s->regs[5 ], &args[1 ],5 *sizeof (long )); +} +static inline int syscall_get_arch (struct task_struct *task) {return AUDIT_ARCH_LOONGARCH64 ;
arch/mips/include/asm/syscall.h +32 -0
@@ -74,6 +74,23 @@ static inline void mips_get_syscall_arg(unsigned long *arg,#endif } +static inline void mips_set_syscall_arg (unsigned long *arg, +struct task_struct *task,struct pt_regs *regs,unsigned int n) +{ +#ifdef CONFIG_32BIT +switch (n) { +case 0 :case 1 :case 2 :case 3 : + regs->regs[4 + n] = *arg; +return ; +case 4 :case 5 :case 6 :case 7 : + *arg = regs->pad0[n] = *arg; +return ; + } +#else + regs->regs[4 + n] = *arg; +#endif +} +static inline long syscall_get_error (struct task_struct *task,struct pt_regs *regs) {
@@ -120,6 +137,21 @@ static inline void syscall_get_arguments(struct task_struct *task,mips_get_syscall_arg (args++, task, regs, i++); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +unsigned long *args) +{ +unsigned int i =0 ; +unsigned int n =6 ; + +/* O32 ABI syscall() */ +if (mips_syscall_is_indirect (task, regs)) + i++; + +while (n--) +mips_set_syscall_arg (args++, task, regs, i++); +} +extern const unsigned long sys_call_table[];extern const unsigned long sys32_call_table[];extern const unsigned long sysn32_call_table[];
arch/nios2/include/asm/syscall.h +11 -0
@@ -58,6 +58,17 @@ static inline void syscall_get_arguments(struct task_struct *task, *args = regs->r9; } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs,const unsigned long *args) +{ + regs->r4 = *args++; + regs->r5 = *args++; + regs->r6 = *args++; + regs->r7 = *args++; + regs->r8 = *args++; + regs->r9 = *args; +} +static inline int syscall_get_arch (struct task_struct *task) {return AUDIT_ARCH_NIOS2 ;
arch/openrisc/include/asm/syscall.h +7 -0
@@ -57,6 +57,13 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,memcpy (args, ®s->gpr[3 ],6 *sizeof (args[0 ])); } +static inline void +syscall_set_arguments (struct task_struct *task,struct pt_regs *regs, +const unsigned long *args) +{ +memcpy (®s->gpr[3 ], args,6 *sizeof (args[0 ])); +} +static inline int syscall_get_arch (struct task_struct *task) {return AUDIT_ARCH_OPENRISC ;
arch/parisc/include/asm/syscall.h +12 -0
@@ -29,6 +29,18 @@ static inline void syscall_get_arguments(struct task_struct *tsk, args[0 ] = regs->gr[26 ]; } +static inline void syscall_set_arguments (struct task_struct *tsk, +struct pt_regs *regs, +unsigned long *args) +{ + regs->gr[21 ] = args[5 ]; + regs->gr[22 ] = args[4 ]; + regs->gr[23 ] = args[3 ]; + regs->gr[24 ] = args[2 ]; + regs->gr[25 ] = args[1 ]; + regs->gr[26 ] = args[0 ]; +} +static inline long syscall_get_error (struct task_struct *task,struct pt_regs *regs) {
arch/powerpc/include/asm/syscall.h +10 -0
@@ -114,6 +114,16 @@ static inline void syscall_get_arguments(struct task_struct *task, } } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +memcpy (®s->gpr[3 ], args,6 *sizeof (args[0 ])); + +/* Also copy the first argument into orig_gpr3 */ + regs->orig_gpr3 = args[0 ]; +} +static inline int syscall_get_arch (struct task_struct *task) {if (is_tsk_32bit_task (task))
arch/riscv/include/asm/syscall.h +9 -0
@@ -66,6 +66,15 @@ static inline void syscall_get_arguments(struct task_struct *task,memcpy (args, ®s->a1,5 *sizeof (args[0 ])); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ + regs->orig_a0 = args[0 ]; + args++; +memcpy (®s->a1, args,5 *sizeof (regs->a1)); +} +static inline int syscall_get_arch (struct task_struct *task) {#ifdef CONFIG_64BIT
arch/s390/include/asm/syscall.h +12 -0
@@ -78,6 +78,18 @@ static inline void syscall_get_arguments(struct task_struct *task, args[0 ] = regs->orig_gpr2 & mask; } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +unsigned int n =6 ; + +while (n-- >0 ) +if (n >0 ) + regs->gprs[2 + n] = args[n]; + regs->orig_gpr2 = args[0 ]; +} +static inline int syscall_get_arch (struct task_struct *task) {#ifdef CONFIG_COMPAT
arch/sh/include/asm/syscall_32.h +12 -0
@@ -57,6 +57,18 @@ static inline void syscall_get_arguments(struct task_struct *task, args[0 ] = regs->regs[4 ]; } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ + regs->regs[1 ] = args[5 ]; + regs->regs[0 ] = args[4 ]; + regs->regs[7 ] = args[3 ]; + regs->regs[6 ] = args[2 ]; + regs->regs[5 ] = args[1 ]; + regs->regs[4 ] = args[0 ]; +} +static inline int syscall_get_arch (struct task_struct *task) {int arch =AUDIT_ARCH_SH ;
arch/sparc/include/asm/syscall.h +10 -0
@@ -117,6 +117,16 @@ static inline void syscall_get_arguments(struct task_struct *task, } } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +unsigned int i; + +for (i =0 ; i <6 ; i++) + regs->u_regs[UREG_I0 + i] = args[i]; +} +static inline int syscall_get_arch (struct task_struct *task) {#if defined(CONFIG_SPARC64 ) && defined(CONFIG_COMPAT )
arch/um/include/asm/syscall-generic.h +14 -0
@@ -62,6 +62,20 @@ static inline void syscall_get_arguments(struct task_struct *task, *args = UPT_SYSCALL_ARG6(r); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +struct uml_pt_regs *r = ®s->regs; + +UPT_SYSCALL_ARG1 (r) = *args++; +UPT_SYSCALL_ARG2 (r) = *args++; +UPT_SYSCALL_ARG3 (r) = *args++; +UPT_SYSCALL_ARG4 (r) = *args++; +UPT_SYSCALL_ARG5 (r) = *args++; +UPT_SYSCALL_ARG6 (r) = *args; +} +/* See arch/x86/um/asm/syscall.h for syscall_get_arch() definition. */ #endif /* __UM_SYSCALL_GENERIC_H */
arch/x86/include/asm/syscall.h +36 -0
@@ -90,6 +90,18 @@ static inline void syscall_get_arguments(struct task_struct *task, args[5 ] = regs->bp; } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ + regs->bx = args[0 ]; + regs->cx = args[1 ]; + regs->dx = args[2 ]; + regs->si = args[3 ]; + regs->di = args[4 ]; + regs->bp = args[5 ]; +} +static inline int syscall_get_arch (struct task_struct *task) {return AUDIT_ARCH_I386 ;
@@ -121,6 +133,30 @@ static inline void syscall_get_arguments(struct task_struct *task, } } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +# ifdef CONFIG_IA32_EMULATION +if (task->thread_info.status &TS_COMPAT ) { + regs->bx = *args++; + regs->cx = *args++; + regs->dx = *args++; + regs->si = *args++; + regs->di = *args++; + regs->bp = *args; + } else +# endif + { + regs->di = *args++; + regs->si = *args++; + regs->dx = *args++; + regs->r10 = *args++; + regs->r8 = *args++; + regs->r9 = *args; + } +} +static inline int syscall_get_arch (struct task_struct *task) {/* x32 tasks should be considered AUDIT_ARCH_X86_64. */
arch/xtensa/include/asm/syscall.h +11 -0
@@ -68,6 +68,17 @@ static inline void syscall_get_arguments(struct task_struct *task, args[i] = regs->areg[reg[i]]; } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +static const unsigned int reg[] =XTENSA_SYSCALL_ARGUMENT_REGS ; +unsigned int i; + +for (i =0 ; i <6 ; ++i) + regs->areg[reg[i]] = args[i]; +} +asmlinkage long xtensa_rt_sigreturn (void );asmlinkage long xtensa_shmat (int ,char __user *,int ); asmlinkage long xtensa_fadvise64_64(int, int,
include/asm-generic/syscall.h +16 -0
@@ -117,6 +117,22 @@ void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,void syscall_get_arguments (struct task_struct *task,struct pt_regs *regs,unsigned long *args); +/** +* syscall_set_arguments - change system call parameter value +* @task: task of interest, must be in system call entry tracing +* @regs: task_pt_regs() of @task +* @args: array of argument values to store +* +* Changes 6 arguments to the system call. +* The first argument gets value @args[0], and so on. +* +* It's only valid to call this when @task is stopped for tracing on +* entry to a system call, due to %SYSCALL_WORK_SYSCALL_TRACE or +* %SYSCALL_WORK_SYSCALL_AUDIT. +*/ +void syscall_set_arguments (struct task_struct *task,struct pt_regs *regs, +const unsigned long *args); +/** * syscall_get_arch - return the AUDIT_ARCH for the current system call * @task: task of interest, must be blocked
Signature · 1 line
ldv
Re: [PATCH v3 2/6] syscall.h: add syscall_set_arguments() and syscall_set_return_value()
Le 28/01/2025 à 10:16, Dmitry V. Levin a écrit :
Quoted 2 lines
These functions are going to be needed on all
HAVE_ARCH_TRACEHOOKarchitectures to implementPTRACE_SET_SYSCALL_INFOAPI.
The subject is misleading. syscall_set_return_value() already exists on most architectures and was not addressed by commit 7962c2eddbfe.
Maybe it would be better to handle syscall_set_return_value() in a separate commit.
Quoted 527 lines
This partially reverts commit
7962c2eddbfe("arch: remove unused functionsyscall_set_arguments()") by reusing some of oldsyscall_set_arguments()implementations.Signed-off-by Dmitry V. Levin <[email protected]>Tested-by Charlie Jenkins <[email protected]>Reviewed-by Charlie Jenkins <[email protected]>--- arch/arc/include/asm/syscall.h | 14 +++++++++++ arch/arm/include/asm/syscall.h | 13 ++++++++++ arch/arm64/include/asm/syscall.h | 13 ++++++++++ arch/csky/include/asm/syscall.h | 13 ++++++++++ arch/hexagon/include/asm/syscall.h | 14 +++++++++++ arch/loongarch/include/asm/syscall.h | 8 ++++++ arch/mips/include/asm/syscall.h | 32 ++++++++++++++++++++++++ arch/nios2/include/asm/syscall.h | 11 ++++++++ arch/openrisc/include/asm/syscall.h | 7 ++++++ arch/parisc/include/asm/syscall.h | 12 +++++++++ arch/powerpc/include/asm/syscall.h | 10 ++++++++ arch/riscv/include/asm/syscall.h | 9 +++++++ arch/s390/include/asm/syscall.h | 12 +++++++++ arch/sh/include/asm/syscall_32.h | 12 +++++++++ arch/sparc/include/asm/syscall.h | 10 ++++++++ arch/um/include/asm/syscall-generic.h | 14 +++++++++++ arch/x86/include/asm/syscall.h | 36 +++++++++++++++++++++++++++ arch/xtensa/include/asm/syscall.h | 11 ++++++++ include/asm-generic/syscall.h | 16 ++++++++++++ 19 files changed, 267 insertions(+)arch/arc/include/asm/syscall.h +14
-0@@ -67,6 +67,20 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, } } +static inline void +syscall_set_arguments (struct task_struct *task,struct pt_regs *regs, +unsigned long *args) +{ +unsigned long *inside_ptregs = ®s->r0; +unsigned int n =6 ; +unsigned int i =0 ; + +while (n--) { + *inside_ptregs = args[i++]; + inside_ptregs--; + } +} +static inline int syscall_get_arch (struct task_struct *task) {arch/arm/include/asm/syscall.h +13
-0@@ -80,6 +80,19 @@ static inline void syscall_get_arguments(struct task_struct *task,memcpy (args, ®s->ARM_r0 +1 ,5 *sizeof (args[0 ])); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +memcpy (®s->ARM_r0, args,6 *sizeof (args[0 ])); +/* +* Also copy the first argument into ARM_ORIG_r0 +* so that syscall_get_arguments() would return it +* instead of the previous value. +*/ + regs->ARM_ORIG_r0 = regs->ARM_r0; +} +static inline int syscall_get_arch (struct task_struct *task) {/* ARM tasks don't change audit architectures on the fly. */ arch/arm64/include/asm/syscall.h +13
-0@@ -73,6 +73,19 @@ static inline void syscall_get_arguments(struct task_struct *task,memcpy (args, ®s->regs[1 ],5 *sizeof (args[0 ])); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +memcpy (®s->regs[0 ], args,6 *sizeof (args[0 ])); +/* +* Also copy the first argument into orig_x0 +* so that syscall_get_arguments() would return it +* instead of the previous value. +*/ + regs->orig_x0 = regs->regs[0 ]; +} +/* * We don't care about endianness (__AUDIT_ARCH_LE bit) here because * AArch64 has the same system calls both on little- and big- endian. arch/csky/include/asm/syscall.h +13
-0@@ -59,6 +59,19 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,memcpy (args, ®s->a1,5 *sizeof (args[0 ])); } +static inline void +syscall_set_arguments (struct task_struct *task,struct pt_regs *regs, +const unsigned long *args) +{ +memcpy (®s->a0, args,6 *sizeof (regs->a0)); +/* +* Also copy the first argument into orig_x0 +* so that syscall_get_arguments() would return it +* instead of the previous value. +*/ + regs->orig_a0 = regs->a0; +} +static inline int syscall_get_arch (struct task_struct *task) {arch/hexagon/include/asm/syscall.h +14
-0@@ -33,6 +33,13 @@ static inline void syscall_get_arguments(struct task_struct *task,memcpy (args, &(®s->r00)[0 ],6 *sizeof (args[0 ])); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +unsigned long *args) +{ +memcpy (&(®s->r00)[0 ], args,6 *sizeof (args[0 ])); +} +static inline long syscall_get_error (struct task_struct *task,struct pt_regs *regs) {@@ -45,6 +52,13 @@ static inline long syscall_get_return_value(struct task_struct *task,return regs->r00; } +static inline void syscall_set_return_value (struct task_struct *task, +struct pt_regs *regs, +int error,long val) +{ + regs->r00 = (long ) error ?: val; +} +static inline int syscall_get_arch (struct task_struct *task) {return AUDIT_ARCH_HEXAGON ;arch/loongarch/include/asm/syscall.h +8
-0@@ -61,6 +61,14 @@ static inline void syscall_get_arguments(struct task_struct *task,memcpy (&args[1 ], ®s->regs[5 ],5 *sizeof (long )); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +unsigned long *args) +{ + regs->orig_a0 = args[0 ]; +memcpy (®s->regs[5 ], &args[1 ],5 *sizeof (long )); +} +static inline int syscall_get_arch (struct task_struct *task) {return AUDIT_ARCH_LOONGARCH64 ;arch/mips/include/asm/syscall.h +32
-0@@ -74,6 +74,23 @@ static inline void mips_get_syscall_arg(unsigned long *arg,#endif } +static inline void mips_set_syscall_arg (unsigned long *arg, +struct task_struct *task,struct pt_regs *regs,unsigned int n) +{ +#ifdef CONFIG_32BIT +switch (n) { +case 0 :case 1 :case 2 :case 3 : + regs->regs[4 + n] = *arg; +return ; +case 4 :case 5 :case 6 :case 7 : + *arg = regs->pad0[n] = *arg; +return ; + } +#else + regs->regs[4 + n] = *arg; +#endif +} +static inline long syscall_get_error (struct task_struct *task,struct pt_regs *regs) {@@ -120,6 +137,21 @@ static inline void syscall_get_arguments(struct task_struct *task,mips_get_syscall_arg (args++, task, regs, i++); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +unsigned long *args) +{ +unsigned int i =0 ; +unsigned int n =6 ; + +/* O32 ABI syscall() */ +if (mips_syscall_is_indirect (task, regs)) + i++; + +while (n--) +mips_set_syscall_arg (args++, task, regs, i++); +} +extern const unsigned long sys_call_table[];extern const unsigned long sys32_call_table[];extern const unsigned long sysn32_call_table[];arch/nios2/include/asm/syscall.h +11
-0@@ -58,6 +58,17 @@ static inline void syscall_get_arguments(struct task_struct *task, *args = regs->r9; } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs,const unsigned long *args) +{ + regs->r4 = *args++; + regs->r5 = *args++; + regs->r6 = *args++; + regs->r7 = *args++; + regs->r8 = *args++; + regs->r9 = *args; +} +static inline int syscall_get_arch (struct task_struct *task) {return AUDIT_ARCH_NIOS2 ;arch/openrisc/include/asm/syscall.h +7
-0@@ -57,6 +57,13 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,memcpy (args, ®s->gpr[3 ],6 *sizeof (args[0 ])); } +static inline void +syscall_set_arguments (struct task_struct *task,struct pt_regs *regs, +const unsigned long *args) +{ +memcpy (®s->gpr[3 ], args,6 *sizeof (args[0 ])); +} +static inline int syscall_get_arch (struct task_struct *task) {return AUDIT_ARCH_OPENRISC ;arch/parisc/include/asm/syscall.h +12
-0@@ -29,6 +29,18 @@ static inline void syscall_get_arguments(struct task_struct *tsk, args[0 ] = regs->gr[26 ]; } +static inline void syscall_set_arguments (struct task_struct *tsk, +struct pt_regs *regs, +unsigned long *args) +{ + regs->gr[21 ] = args[5 ]; + regs->gr[22 ] = args[4 ]; + regs->gr[23 ] = args[3 ]; + regs->gr[24 ] = args[2 ]; + regs->gr[25 ] = args[1 ]; + regs->gr[26 ] = args[0 ]; +} +static inline long syscall_get_error (struct task_struct *task,struct pt_regs *regs) {arch/powerpc/include/asm/syscall.h +10
-0@@ -114,6 +114,16 @@ static inline void syscall_get_arguments(struct task_struct *task, } } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +memcpy (®s->gpr[3 ], args,6 *sizeof (args[0 ])); + +/* Also copy the first argument into orig_gpr3 */ + regs->orig_gpr3 = args[0 ]; +} +static inline int syscall_get_arch (struct task_struct *task) {if (is_tsk_32bit_task (task))arch/riscv/include/asm/syscall.h +9
-0@@ -66,6 +66,15 @@ static inline void syscall_get_arguments(struct task_struct *task,memcpy (args, ®s->a1,5 *sizeof (args[0 ])); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ + regs->orig_a0 = args[0 ]; + args++; +memcpy (®s->a1, args,5 *sizeof (regs->a1)); +} +static inline int syscall_get_arch (struct task_struct *task) {#ifdef CONFIG_64BIT arch/s390/include/asm/syscall.h +12
-0@@ -78,6 +78,18 @@ static inline void syscall_get_arguments(struct task_struct *task, args[0 ] = regs->orig_gpr2 & mask; } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +unsigned int n =6 ; + +while (n-- >0 ) +if (n >0 ) + regs->gprs[2 + n] = args[n]; + regs->orig_gpr2 = args[0 ]; +} +static inline int syscall_get_arch (struct task_struct *task) {#ifdef CONFIG_COMPAT arch/sh/include/asm/syscall_32.h +12
-0@@ -57,6 +57,18 @@ static inline void syscall_get_arguments(struct task_struct *task, args[0 ] = regs->regs[4 ]; } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ + regs->regs[1 ] = args[5 ]; + regs->regs[0 ] = args[4 ]; + regs->regs[7 ] = args[3 ]; + regs->regs[6 ] = args[2 ]; + regs->regs[5 ] = args[1 ]; + regs->regs[4 ] = args[0 ]; +} +static inline int syscall_get_arch (struct task_struct *task) {int arch =AUDIT_ARCH_SH ;arch/sparc/include/asm/syscall.h +10
-0@@ -117,6 +117,16 @@ static inline void syscall_get_arguments(struct task_struct *task, } } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +unsigned int i; + +for (i =0 ; i <6 ; i++) + regs->u_regs[UREG_I0 + i] = args[i]; +} +static inline int syscall_get_arch (struct task_struct *task) {#if defined(CONFIG_SPARC64 ) && defined(CONFIG_COMPAT )arch/um/include/asm/syscall-generic.h +14
-0@@ -62,6 +62,20 @@ static inline void syscall_get_arguments(struct task_struct *task, *args = UPT_SYSCALL_ARG6(r); } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +struct uml_pt_regs *r = ®s->regs; + +UPT_SYSCALL_ARG1 (r) = *args++; +UPT_SYSCALL_ARG2 (r) = *args++; +UPT_SYSCALL_ARG3 (r) = *args++; +UPT_SYSCALL_ARG4 (r) = *args++; +UPT_SYSCALL_ARG5 (r) = *args++; +UPT_SYSCALL_ARG6 (r) = *args; +} +/* See arch/x86/um/asm/syscall.h for syscall_get_arch() definition. */ #endif /* __UM_SYSCALL_GENERIC_H */ arch/x86/include/asm/syscall.h +36
-0@@ -90,6 +90,18 @@ static inline void syscall_get_arguments(struct task_struct *task, args[5 ] = regs->bp; } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ + regs->bx = args[0 ]; + regs->cx = args[1 ]; + regs->dx = args[2 ]; + regs->si = args[3 ]; + regs->di = args[4 ]; + regs->bp = args[5 ]; +} +static inline int syscall_get_arch (struct task_struct *task) {return AUDIT_ARCH_I386 ;@@ -121,6 +133,30 @@ static inline void syscall_get_arguments(struct task_struct *task, } } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +# ifdef CONFIG_IA32_EMULATION +if (task->thread_info.status &TS_COMPAT ) { + regs->bx = *args++; + regs->cx = *args++; + regs->dx = *args++; + regs->si = *args++; + regs->di = *args++; + regs->bp = *args; + } else +# endif + { + regs->di = *args++; + regs->si = *args++; + regs->dx = *args++; + regs->r10 = *args++; + regs->r8 = *args++; + regs->r9 = *args; + } +} +static inline int syscall_get_arch (struct task_struct *task) {/* x32 tasks should be considered AUDIT_ARCH_X86_64. */ arch/xtensa/include/asm/syscall.h +11
-0@@ -68,6 +68,17 @@ static inline void syscall_get_arguments(struct task_struct *task, args[i] = regs->areg[reg[i]]; } +static inline void syscall_set_arguments (struct task_struct *task, +struct pt_regs *regs, +const unsigned long *args) +{ +static const unsigned int reg[] =XTENSA_SYSCALL_ARGUMENT_REGS ; +unsigned int i; + +for (i =0 ; i <6 ; ++i) + regs->areg[reg[i]] = args[i]; +} +asmlinkage long xtensa_rt_sigreturn (void );asmlinkage long xtensa_shmat (int ,char __user *,int ); asmlinkage long xtensa_fadvise64_64(int, int,include/asm-generic/syscall.h +16
-0@@ -117,6 +117,22 @@ void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,void syscall_get_arguments (struct task_struct *task,struct pt_regs *regs,unsigned long *args); +/** +* syscall_set_arguments - change system call parameter value +* @task: task of interest, must be in system call entry tracing +* @regs: task_pt_regs() of @task +* @args: array of argument values to store +* +* Changes 6 arguments to the system call. +* The first argument gets value @args[0], and so on. +* +* It's only valid to call this when @task is stopped for tracing on +* entry to a system call, due to %SYSCALL_WORK_SYSCALL_TRACE or +* %SYSCALL_WORK_SYSCALL_AUDIT. +*/ +void syscall_set_arguments (struct task_struct *task,struct pt_regs *regs, +const unsigned long *args); +/** * syscall_get_arch - return the AUDIT_ARCH for the current system call * @task: task of interest, must be blocked
Re: [PATCH v3 2/6] syscall.h: add syscall_set_arguments() and syscall_set_return_value()
Quoted 9 lines · Christophe Leroy
Le 28/01/2025 à 10:16, Dmitry V. Levin a écrit :
Quoted 2 lines
These functions are going to be needed on all
HAVE_ARCH_TRACEHOOKarchitectures to implementPTRACE_SET_SYSCALL_INFOAPI.The subject is misleading.
syscall_set_return_value()already exists on most architectures and was not addressed by commit7962c2eddbfe.Maybe it would be better to handle
syscall_set_return_value()in a separate commit.
syscall_set_return_value() is being added only on hexagon. I didn't think it worth a separate commit, but it's certainly possible to split this commit into two.
Signature · 1 line
ldv
Sven Schnelle
reviewerRe: [PATCH v3 2/6] syscall.h: add syscall_set_arguments() and syscall_set_return_value()
In reply to Dmitry V. LevinQuoted 41 lines · Dmitry V. Levin
These functions are going to be needed on all
HAVE_ARCH_TRACEHOOKarchitectures to implementPTRACE_SET_SYSCALL_INFOAPI.This partially reverts commit
7962c2eddbfe("arch: remove unused functionsyscall_set_arguments()") by reusing some of oldsyscall_set_arguments()implementations.Signed-off-by Dmitry V. Levin <[email protected]>Tested-by Charlie Jenkins <[email protected]>Reviewed-by Charlie Jenkins <[email protected]>--- arch/arc/include/asm/syscall.h | 14 +++++++++++ arch/arm/include/asm/syscall.h | 13 ++++++++++ arch/arm64/include/asm/syscall.h | 13 ++++++++++ arch/csky/include/asm/syscall.h | 13 ++++++++++ arch/hexagon/include/asm/syscall.h | 14 +++++++++++ arch/loongarch/include/asm/syscall.h | 8 ++++++ arch/mips/include/asm/syscall.h | 32 ++++++++++++++++++++++++ arch/nios2/include/asm/syscall.h | 11 ++++++++ arch/openrisc/include/asm/syscall.h | 7 ++++++ arch/parisc/include/asm/syscall.h | 12 +++++++++ arch/powerpc/include/asm/syscall.h | 10 ++++++++ arch/riscv/include/asm/syscall.h | 9 +++++++ arch/s390/include/asm/syscall.h | 12 +++++++++ arch/sh/include/asm/syscall_32.h | 12 +++++++++ arch/sparc/include/asm/syscall.h | 10 ++++++++ arch/um/include/asm/syscall-generic.h | 14 +++++++++++ arch/x86/include/asm/syscall.h | 36 +++++++++++++++++++++++++++ arch/xtensa/include/asm/syscall.h | 11 ++++++++ include/asm-generic/syscall.h | 16 ++++++++++++ 19 files changed, 267 insertions(+)arch/s390/include/asm/syscall.h +1
-0@@ -78,6 +78,18 @@ static inline void syscall_get_arguments(struct task_struct *task, args[0 ] = regs->orig_gpr2 & mask; } +static inline void syscall_set_arguments(struct task_struct *task,
arch/s390/include/asm/syscall.h static inline void syscall_get_arguments(struct task_struct *task, · line 91
Quoted 10 lines
arch/s390/include/asm/syscall.h +10
-0+struct pt_regs *regs, + const unsigned long *args) +{ + unsigned int n = 6; + +while (n-- >0 ) +if (n >0 ) + regs->gprs[2 + n] = args[n]; + regs->orig_gpr2 = args[0 ]; +}
Could that be changed to something like:
for (int n = 1; n < 6; n++)
regs->gprs[2 + n] = args[n];
regs->orig_gpr2 = args[0];
I think this is way easier to parse.
Re: [PATCH v3 2/6] syscall.h: add syscall_set_arguments() and syscall_set_return_value()
Quoted 56 lines · Sven Schnelle
Quoted 41 lines · Dmitry V. Levin
These functions are going to be needed on all
HAVE_ARCH_TRACEHOOKarchitectures to implementPTRACE_SET_SYSCALL_INFOAPI.This partially reverts commit
7962c2eddbfe("arch: remove unused functionsyscall_set_arguments()") by reusing some of oldsyscall_set_arguments()implementations.Signed-off-by Dmitry V. Levin <[email protected]>Tested-by Charlie Jenkins <[email protected]>Reviewed-by Charlie Jenkins <[email protected]>--- arch/arc/include/asm/syscall.h | 14 +++++++++++ arch/arm/include/asm/syscall.h | 13 ++++++++++ arch/arm64/include/asm/syscall.h | 13 ++++++++++ arch/csky/include/asm/syscall.h | 13 ++++++++++ arch/hexagon/include/asm/syscall.h | 14 +++++++++++ arch/loongarch/include/asm/syscall.h | 8 ++++++ arch/mips/include/asm/syscall.h | 32 ++++++++++++++++++++++++ arch/nios2/include/asm/syscall.h | 11 ++++++++ arch/openrisc/include/asm/syscall.h | 7 ++++++ arch/parisc/include/asm/syscall.h | 12 +++++++++ arch/powerpc/include/asm/syscall.h | 10 ++++++++ arch/riscv/include/asm/syscall.h | 9 +++++++ arch/s390/include/asm/syscall.h | 12 +++++++++ arch/sh/include/asm/syscall_32.h | 12 +++++++++ arch/sparc/include/asm/syscall.h | 10 ++++++++ arch/um/include/asm/syscall-generic.h | 14 +++++++++++ arch/x86/include/asm/syscall.h | 36 +++++++++++++++++++++++++++ arch/xtensa/include/asm/syscall.h | 11 ++++++++ include/asm-generic/syscall.h | 16 ++++++++++++ 19 files changed, 267 insertions(+)arch/s390/include/asm/syscall.h +1
-0@@ -78,6 +78,18 @@ static inline void syscall_get_arguments(struct task_struct *task, args[0 ] = regs->orig_gpr2 & mask; } +static inline void syscall_set_arguments(struct task_struct *task,arch/s390/include/asm/syscall.h static inline void syscall_get_arguments(struct task_struct *task, · line 91
Quoted 10 lines
arch/s390/include/asm/syscall.h +10
-0+struct pt_regs *regs, + const unsigned long *args) +{ + unsigned int n = 6; + +while (n-- >0 ) +if (n >0 ) + regs->gprs[2 + n] = args[n]; + regs->orig_gpr2 = args[0 ]; +}Could that be changed to something like:
Quoted 5 lines
for (int n = 1; n < 6; n++)
regs->gprs[2 + n] = args[n];
regs->orig_gpr2= args[0];I think this is way easier to parse.
I don't mind changing syscall_set_arguments() this way, but it just mirrors syscall_get_arguments(), so I think it would be better if these two functions were written in the same style. Would you like to change syscall_get_arguments() as well?
Signature · 1 line
ldv
Sven Schnelle
reviewerRe: [PATCH v3 2/6] syscall.h: add syscall_set_arguments() and syscall_set_return_value()
Quoted 61 lines · Dmitry V. Levin
Quoted 60 lines · Sven Schnelle
Quoted 41 lines · Dmitry V. Levin
These functions are going to be needed on all
HAVE_ARCH_TRACEHOOKarchitectures to implementPTRACE_SET_SYSCALL_INFOAPI.This partially reverts commit
7962c2eddbfe("arch: remove unused functionsyscall_set_arguments()") by reusing some of oldsyscall_set_arguments()implementations.Signed-off-by Dmitry V. Levin <[email protected]>Tested-by Charlie Jenkins <[email protected]>Reviewed-by Charlie Jenkins <[email protected]>--- arch/arc/include/asm/syscall.h | 14 +++++++++++ arch/arm/include/asm/syscall.h | 13 ++++++++++ arch/arm64/include/asm/syscall.h | 13 ++++++++++ arch/csky/include/asm/syscall.h | 13 ++++++++++ arch/hexagon/include/asm/syscall.h | 14 +++++++++++ arch/loongarch/include/asm/syscall.h | 8 ++++++ arch/mips/include/asm/syscall.h | 32 ++++++++++++++++++++++++ arch/nios2/include/asm/syscall.h | 11 ++++++++ arch/openrisc/include/asm/syscall.h | 7 ++++++ arch/parisc/include/asm/syscall.h | 12 +++++++++ arch/powerpc/include/asm/syscall.h | 10 ++++++++ arch/riscv/include/asm/syscall.h | 9 +++++++ arch/s390/include/asm/syscall.h | 12 +++++++++ arch/sh/include/asm/syscall_32.h | 12 +++++++++ arch/sparc/include/asm/syscall.h | 10 ++++++++ arch/um/include/asm/syscall-generic.h | 14 +++++++++++ arch/x86/include/asm/syscall.h | 36 +++++++++++++++++++++++++++ arch/xtensa/include/asm/syscall.h | 11 ++++++++ include/asm-generic/syscall.h | 16 ++++++++++++ 19 files changed, 267 insertions(+)arch/s390/include/asm/syscall.h +1
-0@@ -78,6 +78,18 @@ static inline void syscall_get_arguments(struct task_struct *task, args[0 ] = regs->orig_gpr2 & mask; } +static inline void syscall_set_arguments(struct task_struct *task,arch/s390/include/asm/syscall.h static inline void syscall_get_arguments(struct task_struct *task, · line 91
Quoted 10 lines
arch/s390/include/asm/syscall.h +10
-0+struct pt_regs *regs, + const unsigned long *args) +{ + unsigned int n = 6; + +while (n-- >0 ) +if (n >0 ) + regs->gprs[2 + n] = args[n]; + regs->orig_gpr2 = args[0 ]; +}Could that be changed to something like:
for (int n = 1; n < 6; n++)
regs->gprs[2 + n] = args[n];
regs->orig_gpr2= args[0];
Quoted 6 lines
Quoted 1 line
I think this is way easier to parse.
I don't mind changing
syscall_set_arguments()this way, but it just mirrorssyscall_get_arguments(), so I think it would be better if these two functions were written in the same style. Would you like to changesyscall_get_arguments()as well?
Oh. I'll prepare a patch for syscall_get_arguments(), wasn't aware that this function looks the same. I'll send this via the s390 tree, so it's independent of your patch series. Thanks!
PATCH v3 3/6 syscall.h: introduce syscall_set_nr()
In reply to Dmitry V. LevinSimilar to syscall_set_arguments() that complements syscall_get_arguments(), introduce syscall_set_nr() that complements syscall_get_nr().
syscall_set_nr() is going to be needed along with syscall_set_arguments() on all HAVE_ARCH_TRACEHOOK architectures to implement PTRACE_SET_SYSCALL_INFO API.
--- arch/arc/include/asm/syscall.h | 11 +++++++++++ arch/arm/include/asm/syscall.h | 24 ++++++++++++++++++++++++ arch/arm64/include/asm/syscall.h | 16 ++++++++++++++++ arch/hexagon/include/asm/syscall.h | 7 +++++++ arch/loongarch/include/asm/syscall.h | 7 +++++++ arch/m68k/include/asm/syscall.h | 7 +++++++ arch/microblaze/include/asm/syscall.h | 7 +++++++ arch/mips/include/asm/syscall.h | 14 ++++++++++++++ arch/nios2/include/asm/syscall.h | 5 +++++ arch/openrisc/include/asm/syscall.h | 6 ++++++ arch/parisc/include/asm/syscall.h | 7 +++++++ arch/powerpc/include/asm/syscall.h | 10 ++++++++++ arch/riscv/include/asm/syscall.h | 7 +++++++ arch/s390/include/asm/syscall.h | 12 ++++++++++++ arch/sh/include/asm/syscall_32.h | 12 ++++++++++++ arch/sparc/include/asm/syscall.h | 12 ++++++++++++ arch/um/include/asm/syscall-generic.h | 5 +++++ arch/x86/include/asm/syscall.h | 7 +++++++ arch/xtensa/include/asm/syscall.h | 7 +++++++ include/asm-generic/syscall.h | 14 ++++++++++++++ 20 files changed, 197 insertions(+)
arch/arc/include/asm/syscall.h +11 -0
@@ -23,6 +23,17 @@ syscall_get_nr(struct task_struct *task, struct pt_regs *regs)return -1 ; } +static inline void +syscall_set_nr (struct task_struct *task,struct pt_regs *regs,int nr) +{ +/* +* Unlike syscall_get_nr(), syscall_set_nr() can be called only when +* the target task is stopped for tracing on entering syscall, so +* there is no need to have the same check syscall_get_nr() has. +*/ + regs->r8 = nr; +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
arch/arm/include/asm/syscall.h +24 -0
@@ -68,6 +68,30 @@ static inline void syscall_set_return_value(struct task_struct *task, regs->ARM_r0 = (long ) error ? error : val; } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ +if (nr ==-1 ) { +task_thread_info (task)->abi_syscall =-1 ; +/* +* When the syscall number is set to -1, the syscall will be +* skipped. In this case the syscall return value has to be +* set explicitly, otherwise the first syscall argument is +* returned as the syscall return value. +*/ +syscall_set_return_value (task, regs, -ENOSYS ,0 ); +return ; + } +if ((IS_ENABLED (CONFIG_AEABI ) && !IS_ENABLED (CONFIG_OABI_COMPAT ))) { +task_thread_info (task)->abi_syscall = nr; +return ; + } +task_thread_info (task)->abi_syscall = + (task_thread_info (task)->abi_syscall & ~__NR_SYSCALL_MASK) | + (nr & __NR_SYSCALL_MASK); +} +#define SYSCALL_MAX_ARGS 7 static inline void syscall_get_arguments(struct task_struct *task,
arch/arm64/include/asm/syscall.h +16 -0
@@ -61,6 +61,22 @@ static inline void syscall_set_return_value(struct task_struct *task, regs->regs[0 ] = val; } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ + regs->syscallno = nr; +if (nr ==-1 ) { +/* +* When the syscall number is set to -1, the syscall will be +* skipped. In this case the syscall return value has to be +* set explicitly, otherwise the first syscall argument is +* returned as the syscall return value. +*/ +syscall_set_return_value (task, regs, -ENOSYS ,0 ); + } +} +#define SYSCALL_MAX_ARGS 6 static inline void syscall_get_arguments(struct task_struct *task,
arch/hexagon/include/asm/syscall.h +7 -0
@@ -26,6 +26,13 @@ static inline long syscall_get_nr(struct task_struct *task,return regs->r06; } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ + regs->r06 = nr; +} +static inline void syscall_get_arguments (struct task_struct *task,struct pt_regs *regs,unsigned long *args)
arch/loongarch/include/asm/syscall.h +7 -0
@@ -26,6 +26,13 @@ static inline long syscall_get_nr(struct task_struct *task,return regs->regs[11 ]; } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ + regs->regs[11 ] = nr; +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
arch/m68k/include/asm/syscall.h +7 -0
@@ -14,6 +14,13 @@ static inline int syscall_get_nr(struct task_struct *task,return regs->orig_d0; } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ + regs->orig_d0 = nr; +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
arch/microblaze/include/asm/syscall.h +7 -0
@@ -14,6 +14,13 @@ static inline long syscall_get_nr(struct task_struct *task,return regs->r12; } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ + regs->r12 = nr; +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
arch/mips/include/asm/syscall.h +14 -0
@@ -41,6 +41,20 @@ static inline long syscall_get_nr(struct task_struct *task,return task_thread_info (task)->syscall; } +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 +* syscall_trace_entry() loads it from there unconditionally. +* +* 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; +} +static inline void mips_syscall_update_nr (struct task_struct *task,struct pt_regs *regs) {
arch/nios2/include/asm/syscall.h +5 -0
@@ -15,6 +15,11 @@ static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)return regs->r2; } +static inline void syscall_set_nr (struct task_struct *task,struct pt_regs *regs,int nr) +{ + regs->r2 = nr; +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
arch/openrisc/include/asm/syscall.h +6 -0
@@ -25,6 +25,12 @@ syscall_get_nr(struct task_struct *task, struct pt_regs *regs)return regs->orig_gpr11; } +static inline void +syscall_set_nr (struct task_struct *task,struct pt_regs *regs,int nr) +{ + regs->orig_gpr11 = nr; +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
arch/parisc/include/asm/syscall.h +7 -0
@@ -17,6 +17,13 @@ static inline long syscall_get_nr(struct task_struct *tsk,return regs->gr[20 ]; } +static inline void syscall_set_nr (struct task_struct *tsk, +struct pt_regs *regs, +int nr) +{ + regs->gr[20 ] = nr; +} +static inline void syscall_get_arguments (struct task_struct *tsk,struct pt_regs *regs,unsigned long *args)
arch/powerpc/include/asm/syscall.h +10 -0
@@ -39,6 +39,16 @@ static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)return -1 ; } +static inline void syscall_set_nr (struct task_struct *task,struct pt_regs *regs,int nr) +{ +/* +* Unlike syscall_get_nr(), syscall_set_nr() can be called only when +* the target task is stopped for tracing on entering syscall, so +* there is no need to have the same check syscall_get_nr() has. +*/ + regs->gpr[0 ] = nr; +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
arch/riscv/include/asm/syscall.h +7 -0
@@ -30,6 +30,13 @@ static inline int syscall_get_nr(struct task_struct *task,return regs->a7; } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ + regs->a7 = nr; +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
arch/s390/include/asm/syscall.h +12 -0
@@ -24,6 +24,18 @@ static inline long syscall_get_nr(struct task_struct *task, (regs->int_code & 0xffff) : -1; } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ +/* +* Unlike syscall_get_nr(), syscall_set_nr() can be called only when +* the target task is stopped for tracing on entering syscall, so +* there is no need to have the same check syscall_get_nr() has. +*/ + regs->int_code = (regs->int_code & ~0xffff ) | (nr &0xffff ); +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
arch/sh/include/asm/syscall_32.h +12 -0
@@ -15,6 +15,18 @@ static inline long syscall_get_nr(struct task_struct *task,return (regs->tra >=0 ) ? regs->regs[3 ] :-1L ; } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ +/* +* Unlike syscall_get_nr(), syscall_set_nr() can be called only when +* the target task is stopped for tracing on entering syscall, so +* there is no need to have the same check syscall_get_nr() has. +*/ + regs->regs[3 ] = nr; +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
arch/sparc/include/asm/syscall.h +12 -0
@@ -25,6 +25,18 @@ static inline long syscall_get_nr(struct task_struct *task,return (syscall_p ? regs->u_regs[UREG_G1 ] :-1L ); } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ +/* +* Unlike syscall_get_nr(), syscall_set_nr() can be called only when +* the target task is stopped for tracing on entering syscall, so +* there is no need to have the same check syscall_get_nr() has. +*/ + regs->u_regs[UREG_G1 ] = nr; +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
arch/um/include/asm/syscall-generic.h +5 -0
@@ -21,6 +21,11 @@ static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)return PT_REGS_SYSCALL_NR (regs); } +static inline void syscall_set_nr (struct task_struct *task,struct pt_regs *regs,int nr) +{ +PT_REGS_SYSCALL_NR (regs) = nr; +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
arch/x86/include/asm/syscall.h +7 -0
@@ -38,6 +38,13 @@ static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)return regs->orig_ax; } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ + regs->orig_ax = nr; +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
arch/xtensa/include/asm/syscall.h +7 -0
@@ -28,6 +28,13 @@ static inline long syscall_get_nr(struct task_struct *task,return regs->syscall; } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ + regs->syscall = nr; +} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
include/asm-generic/syscall.h +14 -0
@@ -37,6 +37,20 @@ struct pt_regs;*/ int syscall_get_nr (struct task_struct *task,struct pt_regs *regs); +/** +* syscall_set_nr - change the system call a task is executing +* @task: task of interest, must be blocked +* @regs: task_pt_regs() of @task +* @nr: system call number +* +* Changes the system call number @task is about to execute. +* +* It's only valid to call this when @task is stopped for tracing on +* entry to a system call, due to %SYSCALL_WORK_SYSCALL_TRACE or +* %SYSCALL_WORK_SYSCALL_AUDIT. +*/ +void syscall_set_nr (struct task_struct *task,struct pt_regs *regs,int nr); +/** * syscall_rollback - roll back registers after an aborted system call * @task: task of interest, must be in system call exit tracing
Signature · 1 line
ldv
Re: [PATCH v3 3/6] syscall.h: introduce syscall_set_nr()
Le 28/01/2025 à 10:16, Dmitry V. Levin a écrit :
Quoted 69 lines
Similar to
syscall_set_arguments()that complementssyscall_get_arguments(), introducesyscall_set_nr()that complementssyscall_get_nr().
syscall_set_nr()is going to be needed along withsyscall_set_arguments()on allHAVE_ARCH_TRACEHOOKarchitectures to implementPTRACE_SET_SYSCALL_INFOAPI.Signed-off-by Dmitry V. Levin <[email protected]>Tested-by Charlie Jenkins <[email protected]>Reviewed-by Charlie Jenkins <[email protected]>--- arch/arc/include/asm/syscall.h | 11 +++++++++++ arch/arm/include/asm/syscall.h | 24 ++++++++++++++++++++++++ arch/arm64/include/asm/syscall.h | 16 ++++++++++++++++ arch/hexagon/include/asm/syscall.h | 7 +++++++ arch/loongarch/include/asm/syscall.h | 7 +++++++ arch/m68k/include/asm/syscall.h | 7 +++++++ arch/microblaze/include/asm/syscall.h | 7 +++++++ arch/mips/include/asm/syscall.h | 14 ++++++++++++++ arch/nios2/include/asm/syscall.h | 5 +++++ arch/openrisc/include/asm/syscall.h | 6 ++++++ arch/parisc/include/asm/syscall.h | 7 +++++++ arch/powerpc/include/asm/syscall.h | 10 ++++++++++ arch/riscv/include/asm/syscall.h | 7 +++++++ arch/s390/include/asm/syscall.h | 12 ++++++++++++ arch/sh/include/asm/syscall_32.h | 12 ++++++++++++ arch/sparc/include/asm/syscall.h | 12 ++++++++++++ arch/um/include/asm/syscall-generic.h | 5 +++++ arch/x86/include/asm/syscall.h | 7 +++++++ arch/xtensa/include/asm/syscall.h | 7 +++++++ include/asm-generic/syscall.h | 14 ++++++++++++++ 20 files changed, 197 insertions(+)arch/arm64/include/asm/syscall.h +16
-0@@ -61,6 +61,22 @@ static inline void syscall_set_return_value(struct task_struct *task, regs->regs[0 ] = val; } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ + regs->syscallno = nr; +if (nr ==-1 ) { +/* +* When the syscall number is set to -1, the syscall will be +* skipped. In this case the syscall return value has to be +* set explicitly, otherwise the first syscall argument is +* returned as the syscall return value. +*/ +syscall_set_return_value (task, regs, -ENOSYS ,0 ); + } +} +#define SYSCALL_MAX_ARGS 6 static inline void syscall_get_arguments(struct task_struct *task,arch/powerpc/include/asm/syscall.h +0
-0@@ -39,6 +39,16 @@ static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)return -1 ;
arch/powerpc/include/asm/syscall.h static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) · line 49
Quoted 10 lines
arch/powerpc/include/asm/syscall.h +8
-0} +static inline void syscall_set_nr (struct task_struct *task,struct pt_regs *regs,int nr) +{ +/* +* Unlike syscall_get_nr(), syscall_set_nr() can be called only when +* the target task is stopped for tracing on entering syscall, so +* there is no need to have the same check syscall_get_nr() has. +*/ + regs->gpr[0 ] = nr;
Doesn't the same as for ARM64 apply here as well ?
Quoted 5 lines
arch/powerpc/include/asm/syscall.h +2
-0+} +static inline void syscall_rollback (struct task_struct *task,struct pt_regs *regs) {
Re: [PATCH v3 3/6] syscall.h: introduce syscall_set_nr()
Quoted 72 lines · Christophe Leroy
Le 28/01/2025 à 10:16, Dmitry V. Levin a écrit :
Quoted 71 lines
Similar to
syscall_set_arguments()that complementssyscall_get_arguments(), introducesyscall_set_nr()that complementssyscall_get_nr().
syscall_set_nr()is going to be needed along withsyscall_set_arguments()on allHAVE_ARCH_TRACEHOOKarchitectures to implementPTRACE_SET_SYSCALL_INFOAPI.Signed-off-by Dmitry V. Levin <[email protected]>Tested-by Charlie Jenkins <[email protected]>Reviewed-by Charlie Jenkins <[email protected]>--- arch/arc/include/asm/syscall.h | 11 +++++++++++ arch/arm/include/asm/syscall.h | 24 ++++++++++++++++++++++++ arch/arm64/include/asm/syscall.h | 16 ++++++++++++++++ arch/hexagon/include/asm/syscall.h | 7 +++++++ arch/loongarch/include/asm/syscall.h | 7 +++++++ arch/m68k/include/asm/syscall.h | 7 +++++++ arch/microblaze/include/asm/syscall.h | 7 +++++++ arch/mips/include/asm/syscall.h | 14 ++++++++++++++ arch/nios2/include/asm/syscall.h | 5 +++++ arch/openrisc/include/asm/syscall.h | 6 ++++++ arch/parisc/include/asm/syscall.h | 7 +++++++ arch/powerpc/include/asm/syscall.h | 10 ++++++++++ arch/riscv/include/asm/syscall.h | 7 +++++++ arch/s390/include/asm/syscall.h | 12 ++++++++++++ arch/sh/include/asm/syscall_32.h | 12 ++++++++++++ arch/sparc/include/asm/syscall.h | 12 ++++++++++++ arch/um/include/asm/syscall-generic.h | 5 +++++ arch/x86/include/asm/syscall.h | 7 +++++++ arch/xtensa/include/asm/syscall.h | 7 +++++++ include/asm-generic/syscall.h | 14 ++++++++++++++ 20 files changed, 197 insertions(+)arch/arm64/include/asm/syscall.h +16
-0@@ -61,6 +61,22 @@ static inline void syscall_set_return_value(struct task_struct *task, regs->regs[0 ] = val; } +static inline void syscall_set_nr (struct task_struct *task, +struct pt_regs *regs, +int nr) +{ + regs->syscallno = nr; +if (nr ==-1 ) { +/* +* When the syscall number is set to -1, the syscall will be +* skipped. In this case the syscall return value has to be +* set explicitly, otherwise the first syscall argument is +* returned as the syscall return value. +*/ +syscall_set_return_value (task, regs, -ENOSYS ,0 ); + } +} +#define SYSCALL_MAX_ARGS 6 static inline void syscall_get_arguments(struct task_struct *task,arch/powerpc/include/asm/syscall.h +0
-0@@ -39,6 +39,16 @@ static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)return -1 ; }
Quoted 10 lines
arch/powerpc/include/asm/syscall.h static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) · line 49
Quoted 8 lines
arch/powerpc/include/asm/syscall.h +8
-0+static inline void syscall_set_nr (struct task_struct *task,struct pt_regs *regs,int nr) +{ +/* +* Unlike syscall_get_nr(), syscall_set_nr() can be called only when +* the target task is stopped for tracing on entering syscall, so +* there is no need to have the same check syscall_get_nr() has. +*/ + regs->gpr[0 ] = nr;Doesn't the same as for ARM64 apply here as well ?
I carefully checked all affected architectures and added that syscall_set_return_value() call only where I think it's needed.
On powerpc it's not needed with the current implementation: their do_seccomp() sets -ENOSYS before __secure_computing() invocation, and their do_syscall_trace_enter() sets -ENOSYS in case of an invalid syscall number.
Signature · 1 line
ldv
PATCH v3 4/6 ptrace_get_syscall_info: factor out ptrace_get_syscall_info_op
In reply to Dmitry V. LevinMove the code that calculates the type of the system call stop out of ptrace_get_syscall_info() into a separate function ptrace_get_syscall_info_op() which is going to be used later to implement PTRACE_SET_SYSCALL_INFO API.
--- kernel/ptrace.c | 58 +++++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 24 deletions(-)
kernel/ptrace.c +34 -24
@@ -921,7 +921,6 @@ ptrace_get_syscall_info_entry(struct task_struct *child, struct pt_regs *regs,unsigned long args[ARRAY_SIZE (info->entry.args)];int i; - info->op =PTRACE_SYSCALL_INFO_ENTRY ; info->entry.nr =syscall_get_nr (child, regs);syscall_get_arguments (child, regs, args);for (i =0 ; i <ARRAY_SIZE (args); i++)
@@ -943,7 +942,6 @@ ptrace_get_syscall_info_seccomp(struct task_struct *child, struct pt_regs *regs,* diverge significantly enough. */ ptrace_get_syscall_info_entry (child, regs, info); - info->op =PTRACE_SYSCALL_INFO_SECCOMP ; info->seccomp.ret_data = child->ptrace_message;/* ret_data is the last field in struct ptrace_syscall_info.seccomp */
@@ -954,7 +952,6 @@ static unsigned long ptrace_get_syscall_info_exit(struct task_struct *child, struct pt_regs *regs, struct ptrace_syscall_info *info) { - info->op = PTRACE_SYSCALL_INFO_EXIT; info->exit.rval = syscall_get_error(child, regs); info->exit.is_error = !!info->exit.rval;if (!info->exit.is_error)
@@ -965,19 +962,8 @@ ptrace_get_syscall_info_exit(struct task_struct *child, struct pt_regs *regs, }static int -ptrace_get_syscall_info (struct task_struct *child,unsigned long user_size, -void __user *datavp) +ptrace_get_syscall_info_op (struct task_struct *child) { -struct pt_regs *regs =task_pt_regs (child); -struct ptrace_syscall_info info = { - .op =PTRACE_SYSCALL_INFO_NONE , - .arch =syscall_get_arch (child), - .instruction_pointer =instruction_pointer (regs), - .stack_pointer =user_stack_pointer (regs), - }; -unsigned long actual_size = offsetof(struct ptrace_syscall_info , entry); -unsigned long write_size; -/* * This does not need lock_task_sighand() to access * child->last_siginfo because ptrace_freeze_traced()
@@ -988,18 +974,42 @@ ptrace_get_syscall_info(struct task_struct *child, unsigned long user_size,case SIGTRAP |0x80 :switch (child->ptrace_message) {case PTRACE_EVENTMSG_SYSCALL_ENTRY : - actual_size =ptrace_get_syscall_info_entry (child, regs, - &info); -break ; +return PTRACE_SYSCALL_INFO_ENTRY ;case PTRACE_EVENTMSG_SYSCALL_EXIT : - actual_size =ptrace_get_syscall_info_exit (child, regs, - &info); -break ; +return PTRACE_SYSCALL_INFO_EXIT ; +default : +return PTRACE_SYSCALL_INFO_NONE ; } -break ;case SIGTRAP | (PTRACE_EVENT_SECCOMP <<8 ): - actual_size =ptrace_get_syscall_info_seccomp (child, regs, - &info); +return PTRACE_SYSCALL_INFO_SECCOMP ; +default : +return PTRACE_SYSCALL_INFO_NONE ; + } +} + +static int +ptrace_get_syscall_info (struct task_struct *child,unsigned long user_size, +void __user *datavp) +{ +struct pt_regs *regs =task_pt_regs (child); +struct ptrace_syscall_info info = { + .op =ptrace_get_syscall_info_op (child), + .arch =syscall_get_arch (child), + .instruction_pointer =instruction_pointer (regs), + .stack_pointer =user_stack_pointer (regs), + }; +unsigned long actual_size = offsetof(struct ptrace_syscall_info , entry); +unsigned long write_size; + +switch (info.op) { +case PTRACE_SYSCALL_INFO_ENTRY : + actual_size =ptrace_get_syscall_info_entry (child, regs, &info); +break ; +case PTRACE_SYSCALL_INFO_EXIT : + actual_size =ptrace_get_syscall_info_exit (child, regs, &info); +break ; +case PTRACE_SYSCALL_INFO_SECCOMP : + actual_size =ptrace_get_syscall_info_seccomp (child, regs, &info);break ; }
Signature · 1 line
ldv
PATCH v3 5/6 ptrace: introduce PTRACE_SET_SYSCALL_INFO request
In reply to Dmitry V. LevinPTRACE_SET_SYSCALL_INFO is a generic ptrace API that complements PTRACE_GET_SYSCALL_INFO by letting the ptracer modify details of system calls the tracee is blocked in.
This API allows ptracers to obtain and modify system call details in a straightforward and architecture-agnostic way.
Current implementation supports changing only those bits of system call information that are used by strace, namely, syscall number, syscall arguments, and syscall return value.
Support of changing additional details returned by PTRACE_GET_SYSCALL_INFO, such as instruction pointer and stack pointer, could be added later if needed, by using struct ptrace_syscall_info.flags to specify the additional details that should be set. Currently, "flags", "reserved", and "seccomp.reserved2" fields of struct ptrace_syscall_info must be initialized with zeroes; "arch", "instruction_pointer", and "stack_pointer" fields are ignored.
PTRACE_SET_SYSCALL_INFO currently supports only PTRACE_SYSCALL_INFO_ENTRY, PTRACE_SYSCALL_INFO_EXIT, and PTRACE_SYSCALL_INFO_SECCOMP operations. Other operations could be added later if needed.
Ideally, PTRACE_SET_SYSCALL_INFO should have been introduced along with PTRACE_GET_SYSCALL_INFO, but it didn't happen. The last straw that convinced me to implement PTRACE_SET_SYSCALL_INFO was apparent failure to provide an API of changing the first system call argument on riscv architecture.
ptrace(2) man page:
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
...PTRACE_SET_SYSCALL_INFO
Modify information about the system call that caused the stop. The "data" argument is a pointer to struct ptrace_syscall_info that specifies the system call information to be set.
The "addr" argument should be set to sizeof(struct ptrace_syscall_info)).
--- include/uapi/linux/ptrace.h | 7 ++- kernel/ptrace.c | 121 +++++++++++++++++++++++++++++++++++- 2 files changed, 126 insertions(+), 2 deletions(-)
include/uapi/linux/ptrace.h +6 -1
@@ -74,6 +74,7 @@ struct seccomp_metadata { };#define PTRACE_GET_SYSCALL_INFO 0x420e +#define PTRACE_SET_SYSCALL_INFO 0x4212#define PTRACE_SYSCALL_INFO_NONE 0#define PTRACE_SYSCALL_INFO_ENTRY 1#define PTRACE_SYSCALL_INFO_EXIT 2
@@ -81,7 +82,8 @@ struct seccomp_metadata {struct ptrace_syscall_info {__u8 op;/* PTRACE_SYSCALL_INFO_* */ -__u8 pad[3 ]; +__u8 reserved; +__u16 flags;__u32 arch;__u64 instruction_pointer;__u64 stack_pointer;
@@ -98,6 +100,7 @@ struct ptrace_syscall_info {__u64 nr;__u64 args[6 ];__u32 ret_data; +__u32 reserved2; } seccomp; }; };
@@ -142,6 +145,8 @@ struct ptrace_sud_config {__u64 len; }; +/* 0x4212 is PTRACE_SET_SYSCALL_INFO */ +/* * These values are stored in task->ptrace_message * by ptrace_stop to describe the current syscall-stop.
kernel/ptrace.c +120 -1
139 lines not on this page · raw message
Signature · 1 line
ldv
Re: [PATCH v3 5/6] ptrace: introduce PTRACE_SET_SYSCALL_INFO request
Le 28/01/2025 à 10:16, Dmitry V. Levin a écrit :
Quoted 10 lines
PTRACE_SET_SYSCALL_INFOis a generic ptrace API that complementsPTRACE_GET_SYSCALL_INFOby letting the ptracer modify details of system calls the tracee is blocked in.This API allows ptracers to obtain and modify system call details in a straightforward and architecture-agnostic way.
Current implementation supports changing only those bits of system call information that are used by strace, namely, syscall number, syscall arguments, and syscall return value.
How do you handle changes related to syscalls that call force_successful_syscall_return() ?
Quoted 224 lines
Support of changing additional details returned by
PTRACE_GET_SYSCALL_INFO, such as instruction pointer and stack pointer, could be added later if needed, by using struct ptrace_syscall_info.flags to specify the additional details that should be set. Currently, "flags", "reserved", and "seccomp.reserved2" fields of structptrace_syscall_infomust be initialized with zeroes; "arch", "instruction_pointer", and "stack_pointer" fields are ignored.
PTRACE_SET_SYSCALL_INFOcurrently supports onlyPTRACE_SYSCALL_INFO_ENTRY,PTRACE_SYSCALL_INFO_EXIT, andPTRACE_SYSCALL_INFO_SECCOMPoperations. Other operations could be added later if needed.Ideally,
PTRACE_SET_SYSCALL_INFOshould have been introduced along withPTRACE_GET_SYSCALL_INFO, but it didn't happen. The last straw that convinced me to implementPTRACE_SET_SYSCALL_INFOwas apparent failure to provide an API of changing the first system call argument on riscv architecture.ptrace(2) man page:
long
ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
...PTRACE_SET_SYSCALL_INFO
Modify information about the system call that caused the stop. The "data" argument is a pointer to structptrace_syscall_infothat specifies the system call information to be set.
The "addr" argument should be set tosizeof(struct ptrace_syscall_info)).Signed-off-by Dmitry V. Levin <[email protected]>Reviewed-by Alexey Gladkov <[email protected]>Reviewed-by Charlie Jenkins <[email protected]>Tested-by Charlie Jenkins <[email protected]>--- include/uapi/linux/ptrace.h | 7 ++- kernel/ptrace.c | 121 +++++++++++++++++++++++++++++++++++- 2 files changed, 126 insertions(+), 2 deletions(-)include/uapi/linux/ptrace.h +6
-1@@ -74,6 +74,7 @@ struct seccomp_metadata { };#define PTRACE_GET_SYSCALL_INFO 0x420e +#define PTRACE_SET_SYSCALL_INFO 0x4212#define PTRACE_SYSCALL_INFO_NONE 0#define PTRACE_SYSCALL_INFO_ENTRY 1#define PTRACE_SYSCALL_INFO_EXIT 2@@ -81,7 +82,8 @@ struct seccomp_metadata {struct ptrace_syscall_info {__u8 op;/* PTRACE_SYSCALL_INFO_* */ -__u8 pad[3 ]; +__u8 reserved; +__u16 flags;__u32 arch;__u64 instruction_pointer;__u64 stack_pointer;@@ -98,6 +100,7 @@ struct ptrace_syscall_info {__u64 nr;__u64 args[6 ];__u32 ret_data; +__u32 reserved2; } seccomp; }; };@@ -142,6 +145,8 @@ struct ptrace_sud_config {__u64 len; }; +/* 0x4212 is PTRACE_SET_SYSCALL_INFO */ +/* * These values are stored in task->ptrace_message * by ptrace_stop to describe the current syscall-stop. kernel/ptrace.c +120
-1@@ -944,7 +944,10 @@ ptrace_get_syscall_info_seccomp(struct task_struct *child, struct pt_regs *regs,ptrace_get_syscall_info_entry (child, regs, info); info->seccomp.ret_data = child->ptrace_message; -/* ret_data is the last field in struct ptrace_syscall_info.seccomp */ +/* +* ret_data is the last non-reserved field +* in struct ptrace_syscall_info.seccomp +*/ return offsetofend(struct ptrace_syscall_info, seccomp.ret_data); }@@ -1016,6 +1019,118 @@ ptrace_get_syscall_info(struct task_struct *child, unsigned long user_size, write_size =min (actual_size, user_size);return copy_to_user (datavp, &info, write_size) ? -EFAULT : actual_size; } + +static int +ptrace_set_syscall_info_entry (struct task_struct *child,struct pt_regs *regs, +struct ptrace_syscall_info *info) +{ +unsigned long args[ARRAY_SIZE (info->entry.args)]; +int nr = info->entry.nr; +int i; + +/* +* Check that the syscall number specified in info->entry.nr +* is either a value of type "int" or a sign-extended value +* of type "int". +*/ +if (nr != info->entry.nr) +return -ERANGE ; + +for (i =0 ; i <ARRAY_SIZE (args); i++) { + args[i] = info->entry.args[i]; +/* +* Check that the syscall argument specified in +* info->entry.args[i] is either a value of type +* "unsigned long" or a sign-extended value of type "long". +*/ +if (args[i] != info->entry.args[i]) +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); + +return 0 ; +} + +static int +ptrace_set_syscall_info_seccomp (struct task_struct *child,struct pt_regs *regs, +struct ptrace_syscall_info *info) +{ +/* +* info->entry is currently a subset of info->seccomp, +* info->seccomp.ret_data is currently ignored. +*/ +return ptrace_set_syscall_info_entry (child, regs, info); +} + +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 ; +} + +static int +ptrace_set_syscall_info (struct task_struct *child,unsigned long user_size, +const void __user *datavp) +{ +struct pt_regs *regs =task_pt_regs (child); +struct ptrace_syscall_info info; + +if (user_size <sizeof (info)) +return -EINVAL ; + +/* +* The compatibility is tracked by info.op and info.flags: if user-space +* does not instruct us to use unknown extra bits from future versions +* of ptrace_syscall_info, we are not going to read them either. +*/ +if (copy_from_user (&info, datavp,sizeof (info))) +return -EFAULT ; + +/* Reserved for future use. */ +if (info.flags || info.reserved || info.seccomp.reserved2) +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 ; + +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); +case PTRACE_SYSCALL_INFO_SECCOMP : +return ptrace_set_syscall_info_seccomp (child, regs, &info); +default : +/* Other types of system call stops are not supported yet. */ +return -EINVAL ; + } +}#endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ int ptrace_request(struct task_struct *child, long request,@@ -1234,6 +1349,10 @@ int ptrace_request(struct task_struct *child, long request,case PTRACE_GET_SYSCALL_INFO : ret =ptrace_get_syscall_info (child, addr, datavp);break ; + +case PTRACE_SET_SYSCALL_INFO : + ret =ptrace_set_syscall_info (child, addr, datavp); +break ;#endif case PTRACE_SECCOMP_GET_FILTER :
Re: [PATCH v3 5/6] ptrace: introduce PTRACE_SET_SYSCALL_INFO request
Quoted 8 lines · Christophe Leroy
Le 28/01/2025 à 10:16, Dmitry V. Levin a écrit :
Quoted 7 lines
PTRACE_SET_SYSCALL_INFOis a generic ptrace API that complementsPTRACE_GET_SYSCALL_INFOby letting the ptracer modify details of system calls the tracee is blocked in.This API allows ptracers to obtain and modify system call details in a straightforward and architecture-agnostic way.
Quoted 6 lines
Quoted 3 lines
Current implementation supports changing only those bits of system call information that are used by strace, namely, syscall number, syscall arguments, and syscall return value.
How do you handle changes related to syscalls that call
force_successful_syscall_return()?
I don't see why these syscalls would need any special treatment. If a tracer wants to set an error status for a syscall that cannot return an error, it's up to the tracer to face the consequences. Tracers can do it now via PTRACE_SETREGS* anyway.
Signature · 1 line
ldv
PATCH v3 6/6 selftests/ptrace: add a test case for PTRACE_SET_SYSCALL_INFO
In reply to Dmitry V. LevinCheck whether PTRACE_SET_SYSCALL_INFO semantics implemented in the kernel matches userspace expectations.
--- tools/testing/selftests/ptrace/Makefile | 2 +- .../selftests/ptrace/set_syscall_info.c | 514 ++++++++++++++++++ 2 files changed, 515 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/ptrace/set_syscall_info.c
tools/testing/selftests/ptrace/Makefile +1 -1
@@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only CFLAGS += -std=c99 -pthread -Wall $(KHDR_INCLUDES) -TEST_GEN_PROGS := get_syscall_info peeksiginfo vmaccess get_set_sud +TEST_GEN_PROGS := get_syscall_info set_syscall_info peeksiginfo vmaccess get_set_sud include ../lib.mk
tools/testing/selftests/ptrace/set_syscall_info.c new file +514 -0
514 lines not on this page · raw message
Signature · 1 line
ldv
Quoted 10 lines · Dmitry V. Levin
* ptrace: Add explicit padding to the end of struct
ptrace_syscall_info, simplify obtaining of userptrace_syscall_info,
do not introducePTRACE_SYSCALL_INFO_SIZE_VER0
* ptrace: Change the return type of ptrace_set_syscall_info_* functions from "unsigned long" to "int"
* ptrace: Add-ERANGEcheck toptrace_set_syscall_info_exit, add comments to-ERANGEchecks
* ptrace: Update comments about supported syscall stops
* selftests: Extendset_syscall_infotest, fix for mips n32
Again, I can't review 1-3, I know nothing about the non-x86 architectures.
As for 4-6, feel free to add