linux-mips.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 2/7] mips: fix mips_get_syscall_arg() for O32 and N32
       [not found] <20250113170925.GA392@strace.io>
@ 2025-01-13 17:11 ` Dmitry V. Levin
  2025-01-14  3:29   ` Maciej W. Rozycki
  2025-01-13 17:11 ` [PATCH v2 3/7] syscall.h: add syscall_set_arguments() and syscall_set_return_value() Dmitry V. Levin
  2025-01-13 17:11 ` [PATCH v2 4/7] syscall.h: introduce syscall_set_nr() Dmitry V. Levin
  2 siblings, 1 reply; 12+ messages in thread
From: Dmitry V. Levin @ 2025-01-13 17:11 UTC (permalink / raw)
  To: Oleg Nesterov, Thomas Bogendoerfer
  Cc: Eugene Syromyatnikov, Mike Frysinger, Renzo Davoli,
	Davide Berardi, strace-devel, linux-mips, linux-kernel

Fix the following 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

Fix the following get_syscall_info test assertion on mips64 O32 and mips64 N32:
  # 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

This makes ptrace/get_syscall_info selftest pass on mips O32,
mips64 O32, and mips64 N32.

Signed-off-by: Dmitry V. Levin <ldv@strace.io>
---

Note that I'm not a MIPS expert, so I cannot tell why the get_user()
approach doesn't work for O32.  Also, during experiments I discovered that
regs->pad0 approach works for O32, but why it works remains a mystery.

 arch/mips/include/asm/syscall.h | 34 ++++++++++-----------------------
 1 file changed, 10 insertions(+), 24 deletions(-)

diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
index ebdf4d910af2..2f85f2d8f754 100644
--- a/arch/mips/include/asm/syscall.h
+++ b/arch/mips/include/asm/syscall.h
@@ -57,37 +57,23 @@ 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)) ||
+	    (IS_ENABLED(CONFIG_MIPS32_N32) &&
+	     test_tsk_thread_flag(task, TIF_32BIT_ADDR)))
+		*arg = (unsigned int)*arg;
+#endif
 }
 
 static inline long syscall_get_error(struct task_struct *task,
-- 
ldv

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 3/7] syscall.h: add syscall_set_arguments() and syscall_set_return_value()
       [not found] <20250113170925.GA392@strace.io>
  2025-01-13 17:11 ` [PATCH v2 2/7] mips: fix mips_get_syscall_arg() for O32 and N32 Dmitry V. Levin
@ 2025-01-13 17:11 ` Dmitry V. Levin
  2025-01-16  2:20   ` Charlie Jenkins
  2025-01-13 17:11 ` [PATCH v2 4/7] syscall.h: introduce syscall_set_nr() Dmitry V. Levin
  2 siblings, 1 reply; 12+ messages in thread
From: Dmitry V. Levin @ 2025-01-13 17:11 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Eugene Syromyatnikov, Mike Frysinger, Renzo Davoli,
	Davide Berardi, strace-devel, Vineet Gupta, Russell King,
	Will Deacon, Guo Ren, Brian Cain, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
	Stafford Horne, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy, Naveen N Rao, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Chris Zankel, Max Filippov, Arnd Bergmann, linux-snps-arc,
	linux-kernel, linux-arm-kernel, linux-csky, linux-hexagon,
	loongarch, linux-mips, linux-openrisc, linux-parisc, linuxppc-dev,
	linux-riscv, linux-s390, linux-sh, sparclinux, linux-um,
	linux-arch

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

Signed-off-by: Dmitry V. Levin <ldv@strace.io>
---

Note that I'm not a MIPS expert, I just added mips_set_syscall_arg() by
looking at mips_get_syscall_arg() and the result passes tests in qemu on
mips O32, mips64 O32, mips64 N32, and mips64 N64.

 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(+)

diff --git a/arch/arc/include/asm/syscall.h b/arch/arc/include/asm/syscall.h
index 9709256e31c8..89c1e1736356 100644
--- a/arch/arc/include/asm/syscall.h
+++ b/arch/arc/include/asm/syscall.h
@@ -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 = &regs->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)
 {
diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h
index fe4326d938c1..21927fa0ae2b 100644
--- a/arch/arm/include/asm/syscall.h
+++ b/arch/arm/include/asm/syscall.h
@@ -80,6 +80,19 @@ static inline void syscall_get_arguments(struct task_struct *task,
 	memcpy(args, &regs->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(&regs->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. */
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index ab8e14b96f68..76020b66286b 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -73,6 +73,19 @@ static inline void syscall_get_arguments(struct task_struct *task,
 	memcpy(args, &regs->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(&regs->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.
diff --git a/arch/csky/include/asm/syscall.h b/arch/csky/include/asm/syscall.h
index 0de5734950bf..30403f7a0487 100644
--- a/arch/csky/include/asm/syscall.h
+++ b/arch/csky/include/asm/syscall.h
@@ -59,6 +59,19 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
 	memcpy(args, &regs->a1, 5 * sizeof(args[0]));
 }
 
+static inline void
+syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
+		      const unsigned long *args)
+{
+	memcpy(&regs->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)
 {
diff --git a/arch/hexagon/include/asm/syscall.h b/arch/hexagon/include/asm/syscall.h
index f6e454f18038..1024a6548d78 100644
--- a/arch/hexagon/include/asm/syscall.h
+++ b/arch/hexagon/include/asm/syscall.h
@@ -33,6 +33,13 @@ static inline void syscall_get_arguments(struct task_struct *task,
 	memcpy(args, &(&regs->r00)[0], 6 * sizeof(args[0]));
 }
 
+static inline void syscall_set_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned long *args)
+{
+	memcpy(&(&regs->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;
diff --git a/arch/loongarch/include/asm/syscall.h b/arch/loongarch/include/asm/syscall.h
index e286dc58476e..ff415b3c0a8e 100644
--- a/arch/loongarch/include/asm/syscall.h
+++ b/arch/loongarch/include/asm/syscall.h
@@ -61,6 +61,14 @@ static inline void syscall_get_arguments(struct task_struct *task,
 	memcpy(&args[1], &regs->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(&regs->regs[5], &args[1], 5 * sizeof(long));
+}
+
 static inline int syscall_get_arch(struct task_struct *task)
 {
 	return AUDIT_ARCH_LOONGARCH64;
diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
index 2f85f2d8f754..3163d1506fae 100644
--- a/arch/mips/include/asm/syscall.h
+++ b/arch/mips/include/asm/syscall.h
@@ -76,6 +76,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)
 {
@@ -122,6 +139,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[];
diff --git a/arch/nios2/include/asm/syscall.h b/arch/nios2/include/asm/syscall.h
index fff52205fb65..526449edd768 100644
--- a/arch/nios2/include/asm/syscall.h
+++ b/arch/nios2/include/asm/syscall.h
@@ -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;
diff --git a/arch/openrisc/include/asm/syscall.h b/arch/openrisc/include/asm/syscall.h
index 903ed882bdec..e6383be2a195 100644
--- a/arch/openrisc/include/asm/syscall.h
+++ b/arch/openrisc/include/asm/syscall.h
@@ -57,6 +57,13 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
 	memcpy(args, &regs->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(&regs->gpr[3], args, 6 * sizeof(args[0]));
+}
+
 static inline int syscall_get_arch(struct task_struct *task)
 {
 	return AUDIT_ARCH_OPENRISC;
diff --git a/arch/parisc/include/asm/syscall.h b/arch/parisc/include/asm/syscall.h
index 00b127a5e09b..b146d0ae4c77 100644
--- a/arch/parisc/include/asm/syscall.h
+++ b/arch/parisc/include/asm/syscall.h
@@ -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)
 {
diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h
index 422d7735ace6..521f279e6b33 100644
--- a/arch/powerpc/include/asm/syscall.h
+++ b/arch/powerpc/include/asm/syscall.h
@@ -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(&regs->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))
diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h
index 121fff429dce..8d389ba995c8 100644
--- a/arch/riscv/include/asm/syscall.h
+++ b/arch/riscv/include/asm/syscall.h
@@ -66,6 +66,15 @@ static inline void syscall_get_arguments(struct task_struct *task,
 	memcpy(args, &regs->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(&regs->a1, args, 5 * sizeof(regs->a1));
+}
+
 static inline int syscall_get_arch(struct task_struct *task)
 {
 #ifdef CONFIG_64BIT
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
index 27e3d804b311..b3dd883699e7 100644
--- a/arch/s390/include/asm/syscall.h
+++ b/arch/s390/include/asm/syscall.h
@@ -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
diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h
index d87738eebe30..cb51a7528384 100644
--- a/arch/sh/include/asm/syscall_32.h
+++ b/arch/sh/include/asm/syscall_32.h
@@ -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;
diff --git a/arch/sparc/include/asm/syscall.h b/arch/sparc/include/asm/syscall.h
index 20c109ac8cc9..62a5a78804c4 100644
--- a/arch/sparc/include/asm/syscall.h
+++ b/arch/sparc/include/asm/syscall.h
@@ -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)
diff --git a/arch/um/include/asm/syscall-generic.h b/arch/um/include/asm/syscall-generic.h
index 172b74143c4b..2984feb9d576 100644
--- a/arch/um/include/asm/syscall-generic.h
+++ b/arch/um/include/asm/syscall-generic.h
@@ -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 = &regs->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 */
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
index 7c488ff0c764..b9c249dd9e3d 100644
--- a/arch/x86/include/asm/syscall.h
+++ b/arch/x86/include/asm/syscall.h
@@ -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. */
diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h
index 5ee974bf8330..f9a671cbf933 100644
--- a/arch/xtensa/include/asm/syscall.h
+++ b/arch/xtensa/include/asm/syscall.h
@@ -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,
diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h
index 5a80fe728dc8..0f7b9a493de7 100644
--- a/include/asm-generic/syscall.h
+++ b/include/asm-generic/syscall.h
@@ -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
-- 
ldv

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 4/7] syscall.h: introduce syscall_set_nr()
       [not found] <20250113170925.GA392@strace.io>
  2025-01-13 17:11 ` [PATCH v2 2/7] mips: fix mips_get_syscall_arg() for O32 and N32 Dmitry V. Levin
  2025-01-13 17:11 ` [PATCH v2 3/7] syscall.h: add syscall_set_arguments() and syscall_set_return_value() Dmitry V. Levin
@ 2025-01-13 17:11 ` Dmitry V. Levin
  2025-01-16  2:20   ` Charlie Jenkins
  2 siblings, 1 reply; 12+ messages in thread
From: Dmitry V. Levin @ 2025-01-13 17:11 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Eugene Syromyatnikov, Mike Frysinger, Renzo Davoli,
	Davide Berardi, strace-devel, Vineet Gupta, Russell King,
	Catalin Marinas, Will Deacon, Brian Cain, Huacai Chen,
	WANG Xuerui, Geert Uytterhoeven, Michal Simek,
	Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
	Stafford Horne, James E.J. Bottomley, Helge Deller,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
	Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Chris Zankel, Max Filippov, Arnd Bergmann, linux-snps-arc,
	linux-kernel, linux-arm-kernel, linux-hexagon, loongarch,
	linux-m68k, linux-mips, linux-openrisc, linux-parisc,
	linuxppc-dev, linux-riscv, linux-s390, linux-sh, sparclinux,
	linux-um, linux-arch

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.

Signed-off-by: Dmitry V. Levin <ldv@strace.io>
---
 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(+)

diff --git a/arch/arc/include/asm/syscall.h b/arch/arc/include/asm/syscall.h
index 89c1e1736356..728d625a10f1 100644
--- a/arch/arc/include/asm/syscall.h
+++ b/arch/arc/include/asm/syscall.h
@@ -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)
 {
diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h
index 21927fa0ae2b..18b102a30741 100644
--- a/arch/arm/include/asm/syscall.h
+++ b/arch/arm/include/asm/syscall.h
@@ -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,
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index 76020b66286b..712daa90e643 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -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,
diff --git a/arch/hexagon/include/asm/syscall.h b/arch/hexagon/include/asm/syscall.h
index 1024a6548d78..70637261817a 100644
--- a/arch/hexagon/include/asm/syscall.h
+++ b/arch/hexagon/include/asm/syscall.h
@@ -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)
diff --git a/arch/loongarch/include/asm/syscall.h b/arch/loongarch/include/asm/syscall.h
index ff415b3c0a8e..81d2733f7b94 100644
--- a/arch/loongarch/include/asm/syscall.h
+++ b/arch/loongarch/include/asm/syscall.h
@@ -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)
 {
diff --git a/arch/m68k/include/asm/syscall.h b/arch/m68k/include/asm/syscall.h
index d1453e850cdd..bf84b160c2eb 100644
--- a/arch/m68k/include/asm/syscall.h
+++ b/arch/m68k/include/asm/syscall.h
@@ -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)
 {
diff --git a/arch/microblaze/include/asm/syscall.h b/arch/microblaze/include/asm/syscall.h
index 5eb3f624cc59..b5b6b91fae3e 100644
--- a/arch/microblaze/include/asm/syscall.h
+++ b/arch/microblaze/include/asm/syscall.h
@@ -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)
 {
diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
index 3163d1506fae..58d68205fd2c 100644
--- a/arch/mips/include/asm/syscall.h
+++ b/arch/mips/include/asm/syscall.h
@@ -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)
 {
diff --git a/arch/nios2/include/asm/syscall.h b/arch/nios2/include/asm/syscall.h
index 526449edd768..8e3eb1d689bb 100644
--- a/arch/nios2/include/asm/syscall.h
+++ b/arch/nios2/include/asm/syscall.h
@@ -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)
 {
diff --git a/arch/openrisc/include/asm/syscall.h b/arch/openrisc/include/asm/syscall.h
index e6383be2a195..5e037d9659c5 100644
--- a/arch/openrisc/include/asm/syscall.h
+++ b/arch/openrisc/include/asm/syscall.h
@@ -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)
 {
diff --git a/arch/parisc/include/asm/syscall.h b/arch/parisc/include/asm/syscall.h
index b146d0ae4c77..c11222798ab2 100644
--- a/arch/parisc/include/asm/syscall.h
+++ b/arch/parisc/include/asm/syscall.h
@@ -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)
diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h
index 521f279e6b33..7505dcfed247 100644
--- a/arch/powerpc/include/asm/syscall.h
+++ b/arch/powerpc/include/asm/syscall.h
@@ -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)
 {
diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h
index 8d389ba995c8..a5281cdf2b10 100644
--- a/arch/riscv/include/asm/syscall.h
+++ b/arch/riscv/include/asm/syscall.h
@@ -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)
 {
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
index b3dd883699e7..12cd0c60c07b 100644
--- a/arch/s390/include/asm/syscall.h
+++ b/arch/s390/include/asm/syscall.h
@@ -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)
 {
diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h
index cb51a7528384..7027d87d901d 100644
--- a/arch/sh/include/asm/syscall_32.h
+++ b/arch/sh/include/asm/syscall_32.h
@@ -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)
 {
diff --git a/arch/sparc/include/asm/syscall.h b/arch/sparc/include/asm/syscall.h
index 62a5a78804c4..b0233924d323 100644
--- a/arch/sparc/include/asm/syscall.h
+++ b/arch/sparc/include/asm/syscall.h
@@ -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)
 {
diff --git a/arch/um/include/asm/syscall-generic.h b/arch/um/include/asm/syscall-generic.h
index 2984feb9d576..bcd73bcfe577 100644
--- a/arch/um/include/asm/syscall-generic.h
+++ b/arch/um/include/asm/syscall-generic.h
@@ -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)
 {
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
index b9c249dd9e3d..c10dbb74cd00 100644
--- a/arch/x86/include/asm/syscall.h
+++ b/arch/x86/include/asm/syscall.h
@@ -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)
 {
diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h
index f9a671cbf933..7db3b489c8ad 100644
--- a/arch/xtensa/include/asm/syscall.h
+++ b/arch/xtensa/include/asm/syscall.h
@@ -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)
 {
diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h
index 0f7b9a493de7..e33fd4e783c1 100644
--- a/include/asm-generic/syscall.h
+++ b/include/asm-generic/syscall.h
@@ -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
-- 
ldv

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 2/7] mips: fix mips_get_syscall_arg() for O32 and N32
  2025-01-13 17:11 ` [PATCH v2 2/7] mips: fix mips_get_syscall_arg() for O32 and N32 Dmitry V. Levin
@ 2025-01-14  3:29   ` Maciej W. Rozycki
  2025-01-14  8:47     ` Dmitry V. Levin
  0 siblings, 1 reply; 12+ messages in thread
From: Maciej W. Rozycki @ 2025-01-14  3:29 UTC (permalink / raw)
  To: Dmitry V. Levin
  Cc: Oleg Nesterov, Thomas Bogendoerfer, Eugene Syromyatnikov,
	Mike Frysinger, Renzo Davoli, Davide Berardi, strace-devel,
	linux-mips, linux-kernel

On Mon, 13 Jan 2025, Dmitry V. Levin wrote:

> Fix the following 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
> 
> Fix the following get_syscall_info test assertion on mips64 O32 and mips64 N32:
>   # 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

 How did you produce these results?

> This makes ptrace/get_syscall_info selftest pass on mips O32,
> mips64 O32, and mips64 N32.
> 
> Signed-off-by: Dmitry V. Levin <ldv@strace.io>
> ---
> 
> Note that I'm not a MIPS expert, so I cannot tell why the get_user()
> approach doesn't work for O32.  Also, during experiments I discovered that
> regs->pad0 approach works for O32, but why it works remains a mystery.

 The patch is definitely broken, the calling convention is the same 
between n32 and n64: 64-bit arguments in $4 through $11 registers as 
required, and your change makes n32 truncate arguments to 32 bits.

 The regs->pad0 approach works due to this piece:

	/*
	 * 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
	.previous

in arch/mips/kernel/scall32-o32.S (and arch/mips/kernel/scall64-o32.S has 
analogous code to adapt to the native n64 calling convention instead), but 
this doesn't seem to me to be the correct approach here.  At first glance 
`mips_get_syscall_arg' does appear fine as it is, so I'd like to know how 
you obtained your results.

  Maciej

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 2/7] mips: fix mips_get_syscall_arg() for O32 and N32
  2025-01-14  3:29   ` Maciej W. Rozycki
@ 2025-01-14  8:47     ` Dmitry V. Levin
  2025-01-14 16:03       ` Maciej W. Rozycki
  0 siblings, 1 reply; 12+ messages in thread
From: Dmitry V. Levin @ 2025-01-14  8:47 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Oleg Nesterov, Thomas Bogendoerfer, Eugene Syromyatnikov,
	Mike Frysinger, Renzo Davoli, Davide Berardi, strace-devel,
	linux-mips, linux-kernel

On Tue, Jan 14, 2025 at 03:29:11AM +0000, Maciej W. Rozycki wrote:
> On Mon, 13 Jan 2025, Dmitry V. Levin wrote:
> 
> > Fix the following 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
> > 
> > Fix the following get_syscall_info test assertion on mips64 O32 and mips64 N32:
> >   # 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
> 
>  How did you produce these results?

$ PATH="$HOME/x-tools/mips64-unknown-linux-gnu/bin:$PATH" make -j`nproc` ARCH=mips CROSS_COMPILE=mips64-unknown-linux-gnu- -C tools/testing/selftests TARGETS=ptrace USERLDFLAGS='-static' USERCFLAGS='-mabi=32'
$ echo init |(cd tools/testing/selftests/ptrace && ln -snf get_syscall_info init && cpio --dereference -o -H newc -R 0:0) |gzip >get_syscall_info.mips-o32.img
$ qemu-system-mips -nographic -kernel vmlinuz -initrd get_syscall_info.mips-o32.img -append 'console=ttyS0'

Likewise for mips64, but the patch for kselftest_harness.h from [1]
is needed to see correct mismatch values in the test diagnostics.

[1] https://lore.kernel.org/all/20250108170757.GA6723@strace.io/

> > This makes ptrace/get_syscall_info selftest pass on mips O32,
> > mips64 O32, and mips64 N32.
> > 
> > Signed-off-by: Dmitry V. Levin <ldv@strace.io>
> > ---
> > 
> > Note that I'm not a MIPS expert, so I cannot tell why the get_user()
> > approach doesn't work for O32.  Also, during experiments I discovered that
> > regs->pad0 approach works for O32, but why it works remains a mystery.
> 
>  The patch is definitely broken, the calling convention is the same 
> between n32 and n64: 64-bit arguments in $4 through $11 registers as 
> required, and your change makes n32 truncate arguments to 32 bits.

There must be something very specific to n32 then: apparently,
__kernel_ulong_t is a 32-bit type on n32, so the syscall arguments are
32-bit values, at some point (in glibc?) they get sign-extended from 32 to
64 bits, and syscall_get_arguments returns them as 64-bit values different
from the original syscall arguments, breaking the test.

If this is the expected behaviour, then I'd have to add an exception for
mips n32 both to the kernel test and to strace that uses this interface.

>  The regs->pad0 approach works due to this piece:
> 
> 	/*
> 	 * 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
> 	.previous
> 
> in arch/mips/kernel/scall32-o32.S (and arch/mips/kernel/scall64-o32.S has 
> analogous code to adapt to the native n64 calling convention instead), but 
> this doesn't seem to me to be the correct approach here.  At first glance 
> `mips_get_syscall_arg' does appear fine as it is, so I'd like to know how 
> you obtained your results.
> 
>   Maciej

-- 
ldv

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 2/7] mips: fix mips_get_syscall_arg() for O32 and N32
  2025-01-14  8:47     ` Dmitry V. Levin
@ 2025-01-14 16:03       ` Maciej W. Rozycki
  2025-01-14 16:42         ` Dmitry V. Levin
  0 siblings, 1 reply; 12+ messages in thread
From: Maciej W. Rozycki @ 2025-01-14 16:03 UTC (permalink / raw)
  To: Dmitry V. Levin
  Cc: Oleg Nesterov, Thomas Bogendoerfer, Eugene Syromyatnikov,
	Mike Frysinger, Renzo Davoli, Davide Berardi, strace-devel,
	linux-mips, linux-kernel

On Tue, 14 Jan 2025, Dmitry V. Levin wrote:

> >  How did you produce these results?
> 
> $ PATH="$HOME/x-tools/mips64-unknown-linux-gnu/bin:$PATH" make -j`nproc` ARCH=mips CROSS_COMPILE=mips64-unknown-linux-gnu- -C tools/testing/selftests TARGETS=ptrace USERLDFLAGS='-static' USERCFLAGS='-mabi=32'
> $ echo init |(cd tools/testing/selftests/ptrace && ln -snf get_syscall_info init && cpio --dereference -o -H newc -R 0:0) |gzip >get_syscall_info.mips-o32.img
> $ qemu-system-mips -nographic -kernel vmlinuz -initrd get_syscall_info.mips-o32.img -append 'console=ttyS0'
> 
> Likewise for mips64, but the patch for kselftest_harness.h from [1]
> is needed to see correct mismatch values in the test diagnostics.
> 
> [1] https://lore.kernel.org/all/20250108170757.GA6723@strace.io/

 Thanks, I'll try to see what's going on with `get_user'.

> >  The patch is definitely broken, the calling convention is the same 
> > between n32 and n64: 64-bit arguments in $4 through $11 registers as 
> > required, and your change makes n32 truncate arguments to 32 bits.
> 
> There must be something very specific to n32 then: apparently,
> __kernel_ulong_t is a 32-bit type on n32, so the syscall arguments are
> 32-bit values, at some point (in glibc?) they get sign-extended from 32 to
> 64 bits, and syscall_get_arguments returns them as 64-bit values different
> from the original syscall arguments, breaking the test.

 This matters at least for `lseek', which has an `off64_t' aka `long long' 
argument on n32 (there's no `_llseek' on n32).  Since arguments are passed 
via 64-bit registers and a `long long' datum is held in just one this is 
transparent between n32 and n64 (of course on n64 this corresponds to the 
plain `long' data type, so the kernel, which is always n64 for 64-bit 
configurations, sees the incoming argument as `long', and the same stands 
for the outgoing return value).

 Surely non-LFS lseek(2) will produce the syscall's `long long' argument 
truncated (cf. sysdeps/unix/sysv/linux/mips/mips64/n32/lseek.c in glibc), 
but both LFS lseek(2) and lseek64(2) will pass the native value on n32.

> If this is the expected behaviour, then I'd have to add an exception for
> mips n32 both to the kernel test and to strace that uses this interface.

 Is MIPS n32 the only psABI across all our architectures supported that 
can have `long long' syscall arguments?  I guess it might actually be the 
case, in which case I won't be surprised it needs specific handling.

  Maciej

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 2/7] mips: fix mips_get_syscall_arg() for O32 and N32
  2025-01-14 16:03       ` Maciej W. Rozycki
@ 2025-01-14 16:42         ` Dmitry V. Levin
  0 siblings, 0 replies; 12+ messages in thread
From: Dmitry V. Levin @ 2025-01-14 16:42 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Oleg Nesterov, Thomas Bogendoerfer, Eugene Syromyatnikov,
	Mike Frysinger, Renzo Davoli, Davide Berardi, strace-devel,
	linux-mips, linux-kernel

On Tue, Jan 14, 2025 at 04:03:28PM +0000, Maciej W. Rozycki wrote:
> On Tue, 14 Jan 2025, Dmitry V. Levin wrote:
> 
> > >  How did you produce these results?
> > 
> > $ PATH="$HOME/x-tools/mips64-unknown-linux-gnu/bin:$PATH" make -j`nproc` ARCH=mips CROSS_COMPILE=mips64-unknown-linux-gnu- -C tools/testing/selftests TARGETS=ptrace USERLDFLAGS='-static' USERCFLAGS='-mabi=32'
> > $ echo init |(cd tools/testing/selftests/ptrace && ln -snf get_syscall_info init && cpio --dereference -o -H newc -R 0:0) |gzip >get_syscall_info.mips-o32.img
> > $ qemu-system-mips -nographic -kernel vmlinuz -initrd get_syscall_info.mips-o32.img -append 'console=ttyS0'
> > 
> > Likewise for mips64, but the patch for kselftest_harness.h from [1]
> > is needed to see correct mismatch values in the test diagnostics.
> > 
> > [1] https://lore.kernel.org/all/20250108170757.GA6723@strace.io/
> 
>  Thanks, I'll try to see what's going on with `get_user'.

Thanks.

> > >  The patch is definitely broken, the calling convention is the same 
> > > between n32 and n64: 64-bit arguments in $4 through $11 registers as 
> > > required, and your change makes n32 truncate arguments to 32 bits.
> > 
> > There must be something very specific to n32 then: apparently,
> > __kernel_ulong_t is a 32-bit type on n32, so the syscall arguments are
> > 32-bit values, at some point (in glibc?) they get sign-extended from 32 to
> > 64 bits, and syscall_get_arguments returns them as 64-bit values different
> > from the original syscall arguments, breaking the test.
> 
>  This matters at least for `lseek', which has an `off64_t' aka `long long' 
> argument on n32 (there's no `_llseek' on n32).  Since arguments are passed 
> via 64-bit registers and a `long long' datum is held in just one this is 
> transparent between n32 and n64 (of course on n64 this corresponds to the 
> plain `long' data type, so the kernel, which is always n64 for 64-bit 
> configurations, sees the incoming argument as `long', and the same stands 
> for the outgoing return value).
> 
>  Surely non-LFS lseek(2) will produce the syscall's `long long' argument 
> truncated (cf. sysdeps/unix/sysv/linux/mips/mips64/n32/lseek.c in glibc), 
> but both LFS lseek(2) and lseek64(2) will pass the native value on n32.
> 
> > If this is the expected behaviour, then I'd have to add an exception for
> > mips n32 both to the kernel test and to strace that uses this interface.
> 
>  Is MIPS n32 the only psABI across all our architectures supported that 
> can have `long long' syscall arguments?  I guess it might actually be the 
> case, in which case I won't be surprised it needs specific handling.

This is very similar to x32, with the only essential difference:
on x32 the 64-bitness of syscall arguments is exposed to userspace via
__kernel_ulong_t:

arch/x86/include/uapi/asm/posix_types_x32.h:typedef unsigned long long __kernel_ulong_t;

In fact, there is a workaround in strace for this case, and now I realized
that it ceased to work on mips n32 long time ago:

# if defined HAVE___KERNEL_LONG_T && defined HAVE___KERNEL_ULONG_T

#  include <asm/posix_types.h>

typedef __kernel_long_t kernel_long_t;
typedef __kernel_ulong_t kernel_ulong_t;

# elif (defined __x86_64__ && defined __ILP32__) || defined LINUX_MIPSN32

typedef long long kernel_long_t;
typedef unsigned long long kernel_ulong_t;

# else

typedef long kernel_long_t;
typedef unsigned long kernel_ulong_t;

# endif


-- 
ldv

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 3/7] syscall.h: add syscall_set_arguments() and syscall_set_return_value()
  2025-01-13 17:11 ` [PATCH v2 3/7] syscall.h: add syscall_set_arguments() and syscall_set_return_value() Dmitry V. Levin
@ 2025-01-16  2:20   ` Charlie Jenkins
  2025-01-17  0:59     ` H. Peter Anvin
  0 siblings, 1 reply; 12+ messages in thread
From: Charlie Jenkins @ 2025-01-16  2:20 UTC (permalink / raw)
  To: Dmitry V. Levin
  Cc: Oleg Nesterov, Eugene Syromyatnikov, Mike Frysinger, Renzo Davoli,
	Davide Berardi, strace-devel, Vineet Gupta, Russell King,
	Will Deacon, Guo Ren, Brian Cain, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
	Stafford Horne, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy, Naveen N Rao, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Chris Zankel, Max Filippov, Arnd Bergmann, linux-snps-arc,
	linux-kernel, linux-arm-kernel, linux-csky, linux-hexagon,
	loongarch, linux-mips, linux-openrisc, linux-parisc, linuxppc-dev,
	linux-riscv, linux-s390, linux-sh, sparclinux, linux-um,
	linux-arch

On Mon, Jan 13, 2025 at 07:11:40PM +0200, Dmitry V. Levin wrote:
> These 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.
> 
> Signed-off-by: Dmitry V. Levin <ldv@strace.io>
> ---
> 
> Note that I'm not a MIPS expert, I just added mips_set_syscall_arg() by
> looking at mips_get_syscall_arg() and the result passes tests in qemu on
> mips O32, mips64 O32, mips64 N32, and mips64 N64.
> 
>  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(+)
> 
> diff --git a/arch/arc/include/asm/syscall.h b/arch/arc/include/asm/syscall.h
> index 9709256e31c8..89c1e1736356 100644
> --- a/arch/arc/include/asm/syscall.h
> +++ b/arch/arc/include/asm/syscall.h
> @@ -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 = &regs->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)
>  {
> diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h
> index fe4326d938c1..21927fa0ae2b 100644
> --- a/arch/arm/include/asm/syscall.h
> +++ b/arch/arm/include/asm/syscall.h
> @@ -80,6 +80,19 @@ static inline void syscall_get_arguments(struct task_struct *task,
>  	memcpy(args, &regs->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(&regs->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. */
> diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
> index ab8e14b96f68..76020b66286b 100644
> --- a/arch/arm64/include/asm/syscall.h
> +++ b/arch/arm64/include/asm/syscall.h
> @@ -73,6 +73,19 @@ static inline void syscall_get_arguments(struct task_struct *task,
>  	memcpy(args, &regs->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(&regs->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.
> diff --git a/arch/csky/include/asm/syscall.h b/arch/csky/include/asm/syscall.h
> index 0de5734950bf..30403f7a0487 100644
> --- a/arch/csky/include/asm/syscall.h
> +++ b/arch/csky/include/asm/syscall.h
> @@ -59,6 +59,19 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
>  	memcpy(args, &regs->a1, 5 * sizeof(args[0]));
>  }
>  
> +static inline void
> +syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
> +		      const unsigned long *args)
> +{
> +	memcpy(&regs->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)
>  {
> diff --git a/arch/hexagon/include/asm/syscall.h b/arch/hexagon/include/asm/syscall.h
> index f6e454f18038..1024a6548d78 100644
> --- a/arch/hexagon/include/asm/syscall.h
> +++ b/arch/hexagon/include/asm/syscall.h
> @@ -33,6 +33,13 @@ static inline void syscall_get_arguments(struct task_struct *task,
>  	memcpy(args, &(&regs->r00)[0], 6 * sizeof(args[0]));
>  }
>  
> +static inline void syscall_set_arguments(struct task_struct *task,
> +					 struct pt_regs *regs,
> +					 unsigned long *args)
> +{
> +	memcpy(&(&regs->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;
> diff --git a/arch/loongarch/include/asm/syscall.h b/arch/loongarch/include/asm/syscall.h
> index e286dc58476e..ff415b3c0a8e 100644
> --- a/arch/loongarch/include/asm/syscall.h
> +++ b/arch/loongarch/include/asm/syscall.h
> @@ -61,6 +61,14 @@ static inline void syscall_get_arguments(struct task_struct *task,
>  	memcpy(&args[1], &regs->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(&regs->regs[5], &args[1], 5 * sizeof(long));
> +}
> +
>  static inline int syscall_get_arch(struct task_struct *task)
>  {
>  	return AUDIT_ARCH_LOONGARCH64;
> diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
> index 2f85f2d8f754..3163d1506fae 100644
> --- a/arch/mips/include/asm/syscall.h
> +++ b/arch/mips/include/asm/syscall.h
> @@ -76,6 +76,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)
>  {
> @@ -122,6 +139,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[];
> diff --git a/arch/nios2/include/asm/syscall.h b/arch/nios2/include/asm/syscall.h
> index fff52205fb65..526449edd768 100644
> --- a/arch/nios2/include/asm/syscall.h
> +++ b/arch/nios2/include/asm/syscall.h
> @@ -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;
> diff --git a/arch/openrisc/include/asm/syscall.h b/arch/openrisc/include/asm/syscall.h
> index 903ed882bdec..e6383be2a195 100644
> --- a/arch/openrisc/include/asm/syscall.h
> +++ b/arch/openrisc/include/asm/syscall.h
> @@ -57,6 +57,13 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
>  	memcpy(args, &regs->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(&regs->gpr[3], args, 6 * sizeof(args[0]));
> +}
> +
>  static inline int syscall_get_arch(struct task_struct *task)
>  {
>  	return AUDIT_ARCH_OPENRISC;
> diff --git a/arch/parisc/include/asm/syscall.h b/arch/parisc/include/asm/syscall.h
> index 00b127a5e09b..b146d0ae4c77 100644
> --- a/arch/parisc/include/asm/syscall.h
> +++ b/arch/parisc/include/asm/syscall.h
> @@ -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)
>  {
> diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h
> index 422d7735ace6..521f279e6b33 100644
> --- a/arch/powerpc/include/asm/syscall.h
> +++ b/arch/powerpc/include/asm/syscall.h
> @@ -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(&regs->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))
> diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h
> index 121fff429dce..8d389ba995c8 100644
> --- a/arch/riscv/include/asm/syscall.h
> +++ b/arch/riscv/include/asm/syscall.h
> @@ -66,6 +66,15 @@ static inline void syscall_get_arguments(struct task_struct *task,
>  	memcpy(args, &regs->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(&regs->a1, args, 5 * sizeof(regs->a1));
> +}

Looks good for riscv.

Tested-by: Charlie Jenkins <charlie@rivosinc.com>
Reviewed-by: Charlie Jenkins <charlie@rivosinc.com

> +
>  static inline int syscall_get_arch(struct task_struct *task)
>  {
>  #ifdef CONFIG_64BIT
> diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
> index 27e3d804b311..b3dd883699e7 100644
> --- a/arch/s390/include/asm/syscall.h
> +++ b/arch/s390/include/asm/syscall.h
> @@ -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
> diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h
> index d87738eebe30..cb51a7528384 100644
> --- a/arch/sh/include/asm/syscall_32.h
> +++ b/arch/sh/include/asm/syscall_32.h
> @@ -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;
> diff --git a/arch/sparc/include/asm/syscall.h b/arch/sparc/include/asm/syscall.h
> index 20c109ac8cc9..62a5a78804c4 100644
> --- a/arch/sparc/include/asm/syscall.h
> +++ b/arch/sparc/include/asm/syscall.h
> @@ -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)
> diff --git a/arch/um/include/asm/syscall-generic.h b/arch/um/include/asm/syscall-generic.h
> index 172b74143c4b..2984feb9d576 100644
> --- a/arch/um/include/asm/syscall-generic.h
> +++ b/arch/um/include/asm/syscall-generic.h
> @@ -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 = &regs->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 */
> diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
> index 7c488ff0c764..b9c249dd9e3d 100644
> --- a/arch/x86/include/asm/syscall.h
> +++ b/arch/x86/include/asm/syscall.h
> @@ -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. */
> diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h
> index 5ee974bf8330..f9a671cbf933 100644
> --- a/arch/xtensa/include/asm/syscall.h
> +++ b/arch/xtensa/include/asm/syscall.h
> @@ -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,
> diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h
> index 5a80fe728dc8..0f7b9a493de7 100644
> --- a/include/asm-generic/syscall.h
> +++ b/include/asm-generic/syscall.h
> @@ -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
> -- 
> ldv

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 4/7] syscall.h: introduce syscall_set_nr()
  2025-01-13 17:11 ` [PATCH v2 4/7] syscall.h: introduce syscall_set_nr() Dmitry V. Levin
@ 2025-01-16  2:20   ` Charlie Jenkins
  0 siblings, 0 replies; 12+ messages in thread
From: Charlie Jenkins @ 2025-01-16  2:20 UTC (permalink / raw)
  To: Dmitry V. Levin
  Cc: Oleg Nesterov, Eugene Syromyatnikov, Mike Frysinger, Renzo Davoli,
	Davide Berardi, strace-devel, Vineet Gupta, Russell King,
	Catalin Marinas, Will Deacon, Brian Cain, Huacai Chen,
	WANG Xuerui, Geert Uytterhoeven, Michal Simek,
	Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
	Stafford Horne, James E.J. Bottomley, Helge Deller,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
	Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Chris Zankel, Max Filippov, Arnd Bergmann, linux-snps-arc,
	linux-kernel, linux-arm-kernel, linux-hexagon, loongarch,
	linux-m68k, linux-mips, linux-openrisc, linux-parisc,
	linuxppc-dev, linux-riscv, linux-s390, linux-sh, sparclinux,
	linux-um, linux-arch

On Mon, Jan 13, 2025 at 07:11:51PM +0200, Dmitry V. Levin wrote:
> 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.
> 
> Signed-off-by: Dmitry V. Levin <ldv@strace.io>
> ---
>  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(+)
> 
> diff --git a/arch/arc/include/asm/syscall.h b/arch/arc/include/asm/syscall.h
> index 89c1e1736356..728d625a10f1 100644
> --- a/arch/arc/include/asm/syscall.h
> +++ b/arch/arc/include/asm/syscall.h
> @@ -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)
>  {
> diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h
> index 21927fa0ae2b..18b102a30741 100644
> --- a/arch/arm/include/asm/syscall.h
> +++ b/arch/arm/include/asm/syscall.h
> @@ -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,
> diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
> index 76020b66286b..712daa90e643 100644
> --- a/arch/arm64/include/asm/syscall.h
> +++ b/arch/arm64/include/asm/syscall.h
> @@ -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,
> diff --git a/arch/hexagon/include/asm/syscall.h b/arch/hexagon/include/asm/syscall.h
> index 1024a6548d78..70637261817a 100644
> --- a/arch/hexagon/include/asm/syscall.h
> +++ b/arch/hexagon/include/asm/syscall.h
> @@ -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)
> diff --git a/arch/loongarch/include/asm/syscall.h b/arch/loongarch/include/asm/syscall.h
> index ff415b3c0a8e..81d2733f7b94 100644
> --- a/arch/loongarch/include/asm/syscall.h
> +++ b/arch/loongarch/include/asm/syscall.h
> @@ -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)
>  {
> diff --git a/arch/m68k/include/asm/syscall.h b/arch/m68k/include/asm/syscall.h
> index d1453e850cdd..bf84b160c2eb 100644
> --- a/arch/m68k/include/asm/syscall.h
> +++ b/arch/m68k/include/asm/syscall.h
> @@ -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)
>  {
> diff --git a/arch/microblaze/include/asm/syscall.h b/arch/microblaze/include/asm/syscall.h
> index 5eb3f624cc59..b5b6b91fae3e 100644
> --- a/arch/microblaze/include/asm/syscall.h
> +++ b/arch/microblaze/include/asm/syscall.h
> @@ -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)
>  {
> diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
> index 3163d1506fae..58d68205fd2c 100644
> --- a/arch/mips/include/asm/syscall.h
> +++ b/arch/mips/include/asm/syscall.h
> @@ -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)
>  {
> diff --git a/arch/nios2/include/asm/syscall.h b/arch/nios2/include/asm/syscall.h
> index 526449edd768..8e3eb1d689bb 100644
> --- a/arch/nios2/include/asm/syscall.h
> +++ b/arch/nios2/include/asm/syscall.h
> @@ -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)
>  {
> diff --git a/arch/openrisc/include/asm/syscall.h b/arch/openrisc/include/asm/syscall.h
> index e6383be2a195..5e037d9659c5 100644
> --- a/arch/openrisc/include/asm/syscall.h
> +++ b/arch/openrisc/include/asm/syscall.h
> @@ -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)
>  {
> diff --git a/arch/parisc/include/asm/syscall.h b/arch/parisc/include/asm/syscall.h
> index b146d0ae4c77..c11222798ab2 100644
> --- a/arch/parisc/include/asm/syscall.h
> +++ b/arch/parisc/include/asm/syscall.h
> @@ -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)
> diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h
> index 521f279e6b33..7505dcfed247 100644
> --- a/arch/powerpc/include/asm/syscall.h
> +++ b/arch/powerpc/include/asm/syscall.h
> @@ -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)
>  {
> diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h
> index 8d389ba995c8..a5281cdf2b10 100644
> --- a/arch/riscv/include/asm/syscall.h
> +++ b/arch/riscv/include/asm/syscall.h
> @@ -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;
> +}

Looks good for riscv.

Tested-by: Charlie Jenkins <charlie@rivosinc.com>
Reviewed-by: Charlie Jenkins <charlie@rivosinc.com>

> +
>  static inline void syscall_rollback(struct task_struct *task,
>  				    struct pt_regs *regs)
>  {
> diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
> index b3dd883699e7..12cd0c60c07b 100644
> --- a/arch/s390/include/asm/syscall.h
> +++ b/arch/s390/include/asm/syscall.h
> @@ -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)
>  {
> diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h
> index cb51a7528384..7027d87d901d 100644
> --- a/arch/sh/include/asm/syscall_32.h
> +++ b/arch/sh/include/asm/syscall_32.h
> @@ -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)
>  {
> diff --git a/arch/sparc/include/asm/syscall.h b/arch/sparc/include/asm/syscall.h
> index 62a5a78804c4..b0233924d323 100644
> --- a/arch/sparc/include/asm/syscall.h
> +++ b/arch/sparc/include/asm/syscall.h
> @@ -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)
>  {
> diff --git a/arch/um/include/asm/syscall-generic.h b/arch/um/include/asm/syscall-generic.h
> index 2984feb9d576..bcd73bcfe577 100644
> --- a/arch/um/include/asm/syscall-generic.h
> +++ b/arch/um/include/asm/syscall-generic.h
> @@ -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)
>  {
> diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
> index b9c249dd9e3d..c10dbb74cd00 100644
> --- a/arch/x86/include/asm/syscall.h
> +++ b/arch/x86/include/asm/syscall.h
> @@ -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)
>  {
> diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h
> index f9a671cbf933..7db3b489c8ad 100644
> --- a/arch/xtensa/include/asm/syscall.h
> +++ b/arch/xtensa/include/asm/syscall.h
> @@ -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)
>  {
> diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h
> index 0f7b9a493de7..e33fd4e783c1 100644
> --- a/include/asm-generic/syscall.h
> +++ b/include/asm-generic/syscall.h
> @@ -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
> -- 
> ldv

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 3/7] syscall.h: add syscall_set_arguments() and syscall_set_return_value()
  2025-01-16  2:20   ` Charlie Jenkins
@ 2025-01-17  0:59     ` H. Peter Anvin
  2025-01-17 15:45       ` Eugene Syromyatnikov
  0 siblings, 1 reply; 12+ messages in thread
From: H. Peter Anvin @ 2025-01-17  0:59 UTC (permalink / raw)
  To: Charlie Jenkins, Dmitry V. Levin
  Cc: Oleg Nesterov, Eugene Syromyatnikov, Mike Frysinger, Renzo Davoli,
	Davide Berardi, strace-devel, Vineet Gupta, Russell King,
	Will Deacon, Guo Ren, Brian Cain, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
	Stafford Horne, James E.J. Bottomley, Helge Deller,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy, Naveen N Rao, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
	John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, Chris Zankel,
	Max Filippov, Arnd Bergmann, linux-snps-arc, linux-kernel,
	linux-arm-kernel, linux-csky, linux-hexagon, loongarch,
	linux-mips, linux-openrisc, linux-parisc, linuxppc-dev,
	linux-riscv, linux-s390, linux-sh, sparclinux, linux-um,
	linux-arch

I link the concept of this patchset, but *please* make it clear in the 
comments that this does not solve the issue of 64-bit kernel arguments 
on 32-bit systems being ABI specific.

This isn't unique to this patch in any way; the only way to handle it is 
by keeping track of each ABI.

On 1/15/25 18:20, Charlie Jenkins wrote:
> On Mon, Jan 13, 2025 at 07:11:40PM +0200, Dmitry V. Levin wrote:
>> These 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.
>>
>> Signed-off-by: Dmitry V. Levin <ldv@strace.io>
>> ---
>>
>> Note that I'm not a MIPS expert, I just added mips_set_syscall_arg() by
>> looking at mips_get_syscall_arg() and the result passes tests in qemu on
>> mips O32, mips64 O32, mips64 N32, and mips64 N64.
>>
>>   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(+)
>>
>> diff --git a/arch/arc/include/asm/syscall.h b/arch/arc/include/asm/syscall.h
>> index 9709256e31c8..89c1e1736356 100644
>> --- a/arch/arc/include/asm/syscall.h
>> +++ b/arch/arc/include/asm/syscall.h
>> @@ -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 = &regs->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)
>>   {
>> diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h
>> index fe4326d938c1..21927fa0ae2b 100644
>> --- a/arch/arm/include/asm/syscall.h
>> +++ b/arch/arm/include/asm/syscall.h
>> @@ -80,6 +80,19 @@ static inline void syscall_get_arguments(struct task_struct *task,
>>   	memcpy(args, &regs->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(&regs->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. */
>> diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
>> index ab8e14b96f68..76020b66286b 100644
>> --- a/arch/arm64/include/asm/syscall.h
>> +++ b/arch/arm64/include/asm/syscall.h
>> @@ -73,6 +73,19 @@ static inline void syscall_get_arguments(struct task_struct *task,
>>   	memcpy(args, &regs->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(&regs->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.
>> diff --git a/arch/csky/include/asm/syscall.h b/arch/csky/include/asm/syscall.h
>> index 0de5734950bf..30403f7a0487 100644
>> --- a/arch/csky/include/asm/syscall.h
>> +++ b/arch/csky/include/asm/syscall.h
>> @@ -59,6 +59,19 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
>>   	memcpy(args, &regs->a1, 5 * sizeof(args[0]));
>>   }
>>   
>> +static inline void
>> +syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
>> +		      const unsigned long *args)
>> +{
>> +	memcpy(&regs->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)
>>   {
>> diff --git a/arch/hexagon/include/asm/syscall.h b/arch/hexagon/include/asm/syscall.h
>> index f6e454f18038..1024a6548d78 100644
>> --- a/arch/hexagon/include/asm/syscall.h
>> +++ b/arch/hexagon/include/asm/syscall.h
>> @@ -33,6 +33,13 @@ static inline void syscall_get_arguments(struct task_struct *task,
>>   	memcpy(args, &(&regs->r00)[0], 6 * sizeof(args[0]));
>>   }
>>   
>> +static inline void syscall_set_arguments(struct task_struct *task,
>> +					 struct pt_regs *regs,
>> +					 unsigned long *args)
>> +{
>> +	memcpy(&(&regs->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;
>> diff --git a/arch/loongarch/include/asm/syscall.h b/arch/loongarch/include/asm/syscall.h
>> index e286dc58476e..ff415b3c0a8e 100644
>> --- a/arch/loongarch/include/asm/syscall.h
>> +++ b/arch/loongarch/include/asm/syscall.h
>> @@ -61,6 +61,14 @@ static inline void syscall_get_arguments(struct task_struct *task,
>>   	memcpy(&args[1], &regs->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(&regs->regs[5], &args[1], 5 * sizeof(long));
>> +}
>> +
>>   static inline int syscall_get_arch(struct task_struct *task)
>>   {
>>   	return AUDIT_ARCH_LOONGARCH64;
>> diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
>> index 2f85f2d8f754..3163d1506fae 100644
>> --- a/arch/mips/include/asm/syscall.h
>> +++ b/arch/mips/include/asm/syscall.h
>> @@ -76,6 +76,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)
>>   {
>> @@ -122,6 +139,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[];
>> diff --git a/arch/nios2/include/asm/syscall.h b/arch/nios2/include/asm/syscall.h
>> index fff52205fb65..526449edd768 100644
>> --- a/arch/nios2/include/asm/syscall.h
>> +++ b/arch/nios2/include/asm/syscall.h
>> @@ -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;
>> diff --git a/arch/openrisc/include/asm/syscall.h b/arch/openrisc/include/asm/syscall.h
>> index 903ed882bdec..e6383be2a195 100644
>> --- a/arch/openrisc/include/asm/syscall.h
>> +++ b/arch/openrisc/include/asm/syscall.h
>> @@ -57,6 +57,13 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
>>   	memcpy(args, &regs->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(&regs->gpr[3], args, 6 * sizeof(args[0]));
>> +}
>> +
>>   static inline int syscall_get_arch(struct task_struct *task)
>>   {
>>   	return AUDIT_ARCH_OPENRISC;
>> diff --git a/arch/parisc/include/asm/syscall.h b/arch/parisc/include/asm/syscall.h
>> index 00b127a5e09b..b146d0ae4c77 100644
>> --- a/arch/parisc/include/asm/syscall.h
>> +++ b/arch/parisc/include/asm/syscall.h
>> @@ -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)
>>   {
>> diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h
>> index 422d7735ace6..521f279e6b33 100644
>> --- a/arch/powerpc/include/asm/syscall.h
>> +++ b/arch/powerpc/include/asm/syscall.h
>> @@ -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(&regs->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))
>> diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h
>> index 121fff429dce..8d389ba995c8 100644
>> --- a/arch/riscv/include/asm/syscall.h
>> +++ b/arch/riscv/include/asm/syscall.h
>> @@ -66,6 +66,15 @@ static inline void syscall_get_arguments(struct task_struct *task,
>>   	memcpy(args, &regs->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(&regs->a1, args, 5 * sizeof(regs->a1));
>> +}
> 
> Looks good for riscv.
> 
> Tested-by: Charlie Jenkins <charlie@rivosinc.com>
> Reviewed-by: Charlie Jenkins <charlie@rivosinc.com
> 
>> +
>>   static inline int syscall_get_arch(struct task_struct *task)
>>   {
>>   #ifdef CONFIG_64BIT
>> diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
>> index 27e3d804b311..b3dd883699e7 100644
>> --- a/arch/s390/include/asm/syscall.h
>> +++ b/arch/s390/include/asm/syscall.h
>> @@ -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
>> diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h
>> index d87738eebe30..cb51a7528384 100644
>> --- a/arch/sh/include/asm/syscall_32.h
>> +++ b/arch/sh/include/asm/syscall_32.h
>> @@ -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;
>> diff --git a/arch/sparc/include/asm/syscall.h b/arch/sparc/include/asm/syscall.h
>> index 20c109ac8cc9..62a5a78804c4 100644
>> --- a/arch/sparc/include/asm/syscall.h
>> +++ b/arch/sparc/include/asm/syscall.h
>> @@ -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)
>> diff --git a/arch/um/include/asm/syscall-generic.h b/arch/um/include/asm/syscall-generic.h
>> index 172b74143c4b..2984feb9d576 100644
>> --- a/arch/um/include/asm/syscall-generic.h
>> +++ b/arch/um/include/asm/syscall-generic.h
>> @@ -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 = &regs->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 */
>> diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
>> index 7c488ff0c764..b9c249dd9e3d 100644
>> --- a/arch/x86/include/asm/syscall.h
>> +++ b/arch/x86/include/asm/syscall.h
>> @@ -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. */
>> diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h
>> index 5ee974bf8330..f9a671cbf933 100644
>> --- a/arch/xtensa/include/asm/syscall.h
>> +++ b/arch/xtensa/include/asm/syscall.h
>> @@ -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,
>> diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h
>> index 5a80fe728dc8..0f7b9a493de7 100644
>> --- a/include/asm-generic/syscall.h
>> +++ b/include/asm-generic/syscall.h
>> @@ -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
>> -- 
>> ldv


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 3/7] syscall.h: add syscall_set_arguments() and syscall_set_return_value()
  2025-01-17  0:59     ` H. Peter Anvin
@ 2025-01-17 15:45       ` Eugene Syromyatnikov
  2025-01-18  4:34         ` H. Peter Anvin
  0 siblings, 1 reply; 12+ messages in thread
From: Eugene Syromyatnikov @ 2025-01-17 15:45 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Charlie Jenkins, Dmitry V. Levin, Oleg Nesterov, Mike Frysinger,
	Renzo Davoli, Davide Berardi, strace-devel, Vineet Gupta,
	Russell King, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
	WANG Xuerui, Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, James E.J. Bottomley,
	Helge Deller, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy, Naveen N Rao, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
	David S. Miller, Andreas Larsson, Richard Weinberger,
	Anton Ivanov, Johannes Berg, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, Dave Hansen, x86, Chris Zankel, Max Filippov,
	Arnd Bergmann, linux-snps-arc, linux-kernel, linux-arm-kernel,
	linux-csky, linux-hexagon, loongarch, linux-mips, linux-openrisc,
	linux-parisc, linuxppc-dev, linux-riscv, linux-s390, linux-sh,
	sparclinux, linux-um, linux-arch

On Fri, Jan 17, 2025 at 2:03 AM H. Peter Anvin <hpa@zytor.com> wrote:
>
> I link the concept of this patchset, but *please* make it clear in the
> comments that this does not solve the issue of 64-bit kernel arguments
> on 32-bit systems being ABI specific.

Sorry, but I don't see how this is relevant; each architecture has its
own ABI with its own set of peculiarities, and there's a lot of
(completely unrelated) work needed in order to make an ABI that is
architecture-agnostic.  All this patch set does is provides a
consistent way to manipulate scno and args across architectures;  it
doesn't address the fact that some architectures have mmap2/mmap_pgoff
syscall, or that some have fadvise64_64 in addition to fadvise64, or
the existence of clone2, or socketcall, or ipc; or that some
architectures don't have open or stat;  or that scnos on different
architectures or even different bit-widths within the "same"
architecture are different.

> This isn't unique to this patch in any way; the only way to handle it is
> by keeping track of each ABI.

That's true, but this patch doesn't even try to address that.

-- 
Eugene Syromyatnikov
mailto:evgsyr@gmail.com
xmpp:esyr@jabber.{ru|org}

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 3/7] syscall.h: add syscall_set_arguments() and syscall_set_return_value()
  2025-01-17 15:45       ` Eugene Syromyatnikov
@ 2025-01-18  4:34         ` H. Peter Anvin
  0 siblings, 0 replies; 12+ messages in thread
From: H. Peter Anvin @ 2025-01-18  4:34 UTC (permalink / raw)
  To: Eugene Syromyatnikov
  Cc: Charlie Jenkins, Dmitry V. Levin, Oleg Nesterov, Mike Frysinger,
	Renzo Davoli, Davide Berardi, strace-devel, Vineet Gupta,
	Russell King, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
	WANG Xuerui, Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn,
	Stefan Kristiansson, Stafford Horne, James E.J. Bottomley,
	Helge Deller, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy, Naveen N Rao, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
	David S. Miller, Andreas Larsson, Richard Weinberger,
	Anton Ivanov, Johannes Berg, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, Dave Hansen, x86, Chris Zankel, Max Filippov,
	Arnd Bergmann, linux-snps-arc, linux-kernel, linux-arm-kernel,
	linux-csky, linux-hexagon, loongarch, linux-mips, linux-openrisc,
	linux-parisc, linuxppc-dev, linux-riscv, linux-s390, linux-sh,
	sparclinux, linux-um, linux-arch

On January 17, 2025 7:45:02 AM PST, Eugene Syromyatnikov <evgsyr@gmail.com> wrote:
>On Fri, Jan 17, 2025 at 2:03 AM H. Peter Anvin <hpa@zytor.com> wrote:
>>
>> I link the concept of this patchset, but *please* make it clear in the
>> comments that this does not solve the issue of 64-bit kernel arguments
>> on 32-bit systems being ABI specific.
>
>Sorry, but I don't see how this is relevant; each architecture has its
>own ABI with its own set of peculiarities, and there's a lot of
>(completely unrelated) work needed in order to make an ABI that is
>architecture-agnostic.  All this patch set does is provides a
>consistent way to manipulate scno and args across architectures;  it
>doesn't address the fact that some architectures have mmap2/mmap_pgoff
>syscall, or that some have fadvise64_64 in addition to fadvise64, or
>the existence of clone2, or socketcall, or ipc; or that some
>architectures don't have open or stat;  or that scnos on different
>architectures or even different bit-widths within the "same"
>architecture are different.
>
>> This isn't unique to this patch in any way; the only way to handle it is
>> by keeping track of each ABI.
>
>That's true, but this patch doesn't even try to address that.
>

I just want it noted in the comment, that's all.

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2025-01-18  4:39 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20250113170925.GA392@strace.io>
2025-01-13 17:11 ` [PATCH v2 2/7] mips: fix mips_get_syscall_arg() for O32 and N32 Dmitry V. Levin
2025-01-14  3:29   ` Maciej W. Rozycki
2025-01-14  8:47     ` Dmitry V. Levin
2025-01-14 16:03       ` Maciej W. Rozycki
2025-01-14 16:42         ` Dmitry V. Levin
2025-01-13 17:11 ` [PATCH v2 3/7] syscall.h: add syscall_set_arguments() and syscall_set_return_value() Dmitry V. Levin
2025-01-16  2:20   ` Charlie Jenkins
2025-01-17  0:59     ` H. Peter Anvin
2025-01-17 15:45       ` Eugene Syromyatnikov
2025-01-18  4:34         ` H. Peter Anvin
2025-01-13 17:11 ` [PATCH v2 4/7] syscall.h: introduce syscall_set_nr() Dmitry V. Levin
2025-01-16  2:20   ` Charlie Jenkins

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).