Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

syscall.h: introduce syscall_set_nr()

Similar 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.

Link: https://lkml.kernel.org/r/20250303112020.GD24170@strace.io
Signed-off-by: Dmitry V. Levin <ldv@strace.io>
Tested-by: Charlie Jenkins <charlie@rivosinc.com>
Reviewed-by: Charlie Jenkins <charlie@rivosinc.com>
Acked-by: Helge Deller <deller@gmx.de> # parisc
Reviewed-by: Maciej W. Rozycki <macro@orcam.me.uk> # mips
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Cc: Alexey Gladkov (Intel) <legion@kernel.org>
Cc: Andreas Larsson <andreas@gaisler.com>
Cc: anton ivanov <anton.ivanov@cambridgegreys.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Borislav Betkov <bp@alien8.de>
Cc: Brian Cain <bcain@quicinc.com>
Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
Cc: Christian Zankel <chris@zankel.net>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Davide Berardi <berardi.dav@gmail.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Dinh Nguyen <dinguyen@kernel.org>
Cc: Eugene Syromiatnikov <esyr@redhat.com>
Cc: Eugene Syromyatnikov <evgsyr@gmail.com>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Guo Ren <guoren@kernel.org>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Huacai Chen <chenhuacai@kernel.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Cc: Jonas Bonn <jonas@southpole.se>
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Max Filippov <jcmvbkbc@gmail.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Michal Simek <monstr@monstr.eu>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Naveen N Rao <naveen@kernel.org>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Renzo Davoi <renzo@cs.unibo.it>
Cc: Richard Weinberger <richard@nod.at>
Cc: Rich Felker <dalias@libc.org>
Cc: Russel King <linux@armlinux.org.uk>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Stafford Horne <shorne@gmail.com>
Cc: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
Cc: Sven Schnelle <svens@linux.ibm.com>
Cc: Thomas Gleinxer <tglx@linutronix.de>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Vineet Gupta <vgupta@kernel.org>
Cc: WANG Xuerui <kernel@xen0n.name>
Cc: Will Deacon <will@kernel.org>
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Dmitry V. Levin and committed by
Andrew Morton
cc662273 17fc7b8f

+198
+11
arch/arc/include/asm/syscall.h
··· 24 24 } 25 25 26 26 static inline void 27 + syscall_set_nr(struct task_struct *task, struct pt_regs *regs, int nr) 28 + { 29 + /* 30 + * Unlike syscall_get_nr(), syscall_set_nr() can be called only when 31 + * the target task is stopped for tracing on entering syscall, so 32 + * there is no need to have the same check syscall_get_nr() has. 33 + */ 34 + regs->r8 = nr; 35 + } 36 + 37 + static inline void 27 38 syscall_rollback(struct task_struct *task, struct pt_regs *regs) 28 39 { 29 40 regs->r0 = regs->orig_r0;
+24
arch/arm/include/asm/syscall.h
··· 68 68 regs->ARM_r0 = (long) error ? error : val; 69 69 } 70 70 71 + static inline void syscall_set_nr(struct task_struct *task, 72 + struct pt_regs *regs, 73 + int nr) 74 + { 75 + if (nr == -1) { 76 + task_thread_info(task)->abi_syscall = -1; 77 + /* 78 + * When the syscall number is set to -1, the syscall will be 79 + * skipped. In this case the syscall return value has to be 80 + * set explicitly, otherwise the first syscall argument is 81 + * returned as the syscall return value. 82 + */ 83 + syscall_set_return_value(task, regs, -ENOSYS, 0); 84 + return; 85 + } 86 + if ((IS_ENABLED(CONFIG_AEABI) && !IS_ENABLED(CONFIG_OABI_COMPAT))) { 87 + task_thread_info(task)->abi_syscall = nr; 88 + return; 89 + } 90 + task_thread_info(task)->abi_syscall = 91 + (task_thread_info(task)->abi_syscall & ~__NR_SYSCALL_MASK) | 92 + (nr & __NR_SYSCALL_MASK); 93 + } 94 + 71 95 #define SYSCALL_MAX_ARGS 7 72 96 73 97 static inline void syscall_get_arguments(struct task_struct *task,
+16
arch/arm64/include/asm/syscall.h
··· 61 61 regs->regs[0] = val; 62 62 } 63 63 64 + static inline void syscall_set_nr(struct task_struct *task, 65 + struct pt_regs *regs, 66 + int nr) 67 + { 68 + regs->syscallno = nr; 69 + if (nr == -1) { 70 + /* 71 + * When the syscall number is set to -1, the syscall will be 72 + * skipped. In this case the syscall return value has to be 73 + * set explicitly, otherwise the first syscall argument is 74 + * returned as the syscall return value. 75 + */ 76 + syscall_set_return_value(task, regs, -ENOSYS, 0); 77 + } 78 + } 79 + 64 80 #define SYSCALL_MAX_ARGS 6 65 81 66 82 static inline void syscall_get_arguments(struct task_struct *task,
+7
arch/hexagon/include/asm/syscall.h
··· 26 26 return regs->r06; 27 27 } 28 28 29 + static inline void syscall_set_nr(struct task_struct *task, 30 + struct pt_regs *regs, 31 + int nr) 32 + { 33 + regs->r06 = nr; 34 + } 35 + 29 36 static inline void syscall_get_arguments(struct task_struct *task, 30 37 struct pt_regs *regs, 31 38 unsigned long *args)
+7
arch/loongarch/include/asm/syscall.h
··· 26 26 return regs->regs[11]; 27 27 } 28 28 29 + static inline void syscall_set_nr(struct task_struct *task, 30 + struct pt_regs *regs, 31 + int nr) 32 + { 33 + regs->regs[11] = nr; 34 + } 35 + 29 36 static inline void syscall_rollback(struct task_struct *task, 30 37 struct pt_regs *regs) 31 38 {
+7
arch/m68k/include/asm/syscall.h
··· 14 14 return regs->orig_d0; 15 15 } 16 16 17 + static inline void syscall_set_nr(struct task_struct *task, 18 + struct pt_regs *regs, 19 + int nr) 20 + { 21 + regs->orig_d0 = nr; 22 + } 23 + 17 24 static inline void syscall_rollback(struct task_struct *task, 18 25 struct pt_regs *regs) 19 26 {
+7
arch/microblaze/include/asm/syscall.h
··· 14 14 return regs->r12; 15 15 } 16 16 17 + static inline void syscall_set_nr(struct task_struct *task, 18 + struct pt_regs *regs, 19 + int nr) 20 + { 21 + regs->r12 = nr; 22 + } 23 + 17 24 static inline void syscall_rollback(struct task_struct *task, 18 25 struct pt_regs *regs) 19 26 {
+15
arch/mips/include/asm/syscall.h
··· 41 41 return task_thread_info(task)->syscall; 42 42 } 43 43 44 + static inline void syscall_set_nr(struct task_struct *task, 45 + struct pt_regs *regs, 46 + int nr) 47 + { 48 + /* 49 + * New syscall number has to be assigned to regs[2] because 50 + * it is loaded from there unconditionally after return from 51 + * syscall_trace_enter() invocation. 52 + * 53 + * Consequently, if the syscall was indirect and nr != __NR_syscall, 54 + * then after this assignment the syscall will cease to be indirect. 55 + */ 56 + task_thread_info(task)->syscall = regs->regs[2] = nr; 57 + } 58 + 44 59 static inline void mips_syscall_update_nr(struct task_struct *task, 45 60 struct pt_regs *regs) 46 61 {
+5
arch/nios2/include/asm/syscall.h
··· 15 15 return regs->r2; 16 16 } 17 17 18 + static inline void syscall_set_nr(struct task_struct *task, struct pt_regs *regs, int nr) 19 + { 20 + regs->r2 = nr; 21 + } 22 + 18 23 static inline void syscall_rollback(struct task_struct *task, 19 24 struct pt_regs *regs) 20 25 {
+6
arch/openrisc/include/asm/syscall.h
··· 26 26 } 27 27 28 28 static inline void 29 + syscall_set_nr(struct task_struct *task, struct pt_regs *regs, int nr) 30 + { 31 + regs->orig_gpr11 = nr; 32 + } 33 + 34 + static inline void 29 35 syscall_rollback(struct task_struct *task, struct pt_regs *regs) 30 36 { 31 37 regs->gpr[11] = regs->orig_gpr11;
+7
arch/parisc/include/asm/syscall.h
··· 17 17 return regs->gr[20]; 18 18 } 19 19 20 + static inline void syscall_set_nr(struct task_struct *tsk, 21 + struct pt_regs *regs, 22 + int nr) 23 + { 24 + regs->gr[20] = nr; 25 + } 26 + 20 27 static inline void syscall_get_arguments(struct task_struct *tsk, 21 28 struct pt_regs *regs, 22 29 unsigned long *args)
+10
arch/powerpc/include/asm/syscall.h
··· 39 39 return -1; 40 40 } 41 41 42 + static inline void syscall_set_nr(struct task_struct *task, struct pt_regs *regs, int nr) 43 + { 44 + /* 45 + * Unlike syscall_get_nr(), syscall_set_nr() can be called only when 46 + * the target task is stopped for tracing on entering syscall, so 47 + * there is no need to have the same check syscall_get_nr() has. 48 + */ 49 + regs->gpr[0] = nr; 50 + } 51 + 42 52 static inline void syscall_rollback(struct task_struct *task, 43 53 struct pt_regs *regs) 44 54 {
+7
arch/riscv/include/asm/syscall.h
··· 30 30 return regs->a7; 31 31 } 32 32 33 + static inline void syscall_set_nr(struct task_struct *task, 34 + struct pt_regs *regs, 35 + int nr) 36 + { 37 + regs->a7 = nr; 38 + } 39 + 33 40 static inline void syscall_rollback(struct task_struct *task, 34 41 struct pt_regs *regs) 35 42 {
+12
arch/s390/include/asm/syscall.h
··· 24 24 (regs->int_code & 0xffff) : -1; 25 25 } 26 26 27 + static inline void syscall_set_nr(struct task_struct *task, 28 + struct pt_regs *regs, 29 + int nr) 30 + { 31 + /* 32 + * Unlike syscall_get_nr(), syscall_set_nr() can be called only when 33 + * the target task is stopped for tracing on entering syscall, so 34 + * there is no need to have the same check syscall_get_nr() has. 35 + */ 36 + regs->int_code = (regs->int_code & ~0xffff) | (nr & 0xffff); 37 + } 38 + 27 39 static inline void syscall_rollback(struct task_struct *task, 28 40 struct pt_regs *regs) 29 41 {
+12
arch/sh/include/asm/syscall_32.h
··· 15 15 return (regs->tra >= 0) ? regs->regs[3] : -1L; 16 16 } 17 17 18 + static inline void syscall_set_nr(struct task_struct *task, 19 + struct pt_regs *regs, 20 + int nr) 21 + { 22 + /* 23 + * Unlike syscall_get_nr(), syscall_set_nr() can be called only when 24 + * the target task is stopped for tracing on entering syscall, so 25 + * there is no need to have the same check syscall_get_nr() has. 26 + */ 27 + regs->regs[3] = nr; 28 + } 29 + 18 30 static inline void syscall_rollback(struct task_struct *task, 19 31 struct pt_regs *regs) 20 32 {
+12
arch/sparc/include/asm/syscall.h
··· 25 25 return (syscall_p ? regs->u_regs[UREG_G1] : -1L); 26 26 } 27 27 28 + static inline void syscall_set_nr(struct task_struct *task, 29 + struct pt_regs *regs, 30 + int nr) 31 + { 32 + /* 33 + * Unlike syscall_get_nr(), syscall_set_nr() can be called only when 34 + * the target task is stopped for tracing on entering syscall, so 35 + * there is no need to have the same check syscall_get_nr() has. 36 + */ 37 + regs->u_regs[UREG_G1] = nr; 38 + } 39 + 28 40 static inline void syscall_rollback(struct task_struct *task, 29 41 struct pt_regs *regs) 30 42 {
+5
arch/um/include/asm/syscall-generic.h
··· 21 21 return PT_REGS_SYSCALL_NR(regs); 22 22 } 23 23 24 + static inline void syscall_set_nr(struct task_struct *task, struct pt_regs *regs, int nr) 25 + { 26 + PT_REGS_SYSCALL_NR(regs) = nr; 27 + } 28 + 24 29 static inline void syscall_rollback(struct task_struct *task, 25 30 struct pt_regs *regs) 26 31 {
+7
arch/x86/include/asm/syscall.h
··· 38 38 return regs->orig_ax; 39 39 } 40 40 41 + static inline void syscall_set_nr(struct task_struct *task, 42 + struct pt_regs *regs, 43 + int nr) 44 + { 45 + regs->orig_ax = nr; 46 + } 47 + 41 48 static inline void syscall_rollback(struct task_struct *task, 42 49 struct pt_regs *regs) 43 50 {
+7
arch/xtensa/include/asm/syscall.h
··· 28 28 return regs->syscall; 29 29 } 30 30 31 + static inline void syscall_set_nr(struct task_struct *task, 32 + struct pt_regs *regs, 33 + int nr) 34 + { 35 + regs->syscall = nr; 36 + } 37 + 31 38 static inline void syscall_rollback(struct task_struct *task, 32 39 struct pt_regs *regs) 33 40 {
+14
include/asm-generic/syscall.h
··· 38 38 int syscall_get_nr(struct task_struct *task, struct pt_regs *regs); 39 39 40 40 /** 41 + * syscall_set_nr - change the system call a task is executing 42 + * @task: task of interest, must be blocked 43 + * @regs: task_pt_regs() of @task 44 + * @nr: system call number 45 + * 46 + * Changes the system call number @task is about to execute. 47 + * 48 + * It's only valid to call this when @task is stopped for tracing on 49 + * entry to a system call, due to %SYSCALL_WORK_SYSCALL_TRACE or 50 + * %SYSCALL_WORK_SYSCALL_AUDIT. 51 + */ 52 + void syscall_set_nr(struct task_struct *task, struct pt_regs *regs, int nr); 53 + 54 + /** 41 55 * syscall_rollback - roll back registers after an aborted system call 42 56 * @task: task of interest, must be in system call exit tracing 43 57 * @regs: task_pt_regs() of @task