diff mbox series

[v5,1/7] mips: fix mips_get_syscall_arg() for o32

Message ID 20250210113442.GB887@strace.io (mailing list archive)
State Superseded
Headers show
Series ptrace: introduce PTRACE_SET_SYSCALL_INFO API | expand

Commit Message

Dmitry V. Levin Feb. 10, 2025, 11:34 a.m. UTC
This makes ptrace/get_syscall_info selftest pass on mips o32 and
mips64 o32 by fixing the following two test assertions:

1. get_syscall_info test assertion on mips o32:
  # get_syscall_info.c:218:get_syscall_info:Expected exp_args[5] (3134521044) == info.entry.args[4] (4911432)
  # get_syscall_info.c:219:get_syscall_info:wait #1: entry stop mismatch

2. get_syscall_info test assertion on mips64 o32:
  # get_syscall_info.c:209:get_syscall_info:Expected exp_args[2] (3134324433) == info.entry.args[1] (18446744072548908753)
  # get_syscall_info.c:210:get_syscall_info:wait #1: entry stop mismatch

The first assertion is fixed for mips o32 by using struct pt_regs.pad0
instead of get_user() to obtain syscall arguments.  This approach works
due to this piece in arch/mips/kernel/scall32-o32.S:

        /*
         * Ok, copy the args from the luser stack to the kernel stack.
         */

        .set    push
        .set    noreorder
        .set    nomacro

    load_a4: user_lw(t5, 16(t0))		# argument #5 from usp
    load_a5: user_lw(t6, 20(t0))		# argument #6 from usp
    load_a6: user_lw(t7, 24(t0))		# argument #7 from usp
    load_a7: user_lw(t8, 28(t0))		# argument #8 from usp
    loads_done:

        sw	t5, 16(sp)		# argument #5 to ksp
        sw	t6, 20(sp)		# argument #6 to ksp
        sw	t7, 24(sp)		# argument #7 to ksp
        sw	t8, 28(sp)		# argument #8 to ksp
        .set	pop

        .section __ex_table,"a"
        PTR_WD	load_a4, bad_stack_a4
        PTR_WD	load_a5, bad_stack_a5
        PTR_WD	load_a6, bad_stack_a6
        PTR_WD	load_a7, bad_stack_a7
        .previous

arch/mips/kernel/scall64-o32.S has analogous code for mips64 o32 that
allows obtaining syscall arguments from struct pt_regs.regs[4..11]
instead of get_user().

The second assertion is fixed by truncating 64-bit values to 32-bit
syscall arguments.

Signed-off-by: Dmitry V. Levin <ldv@strace.io>
---
 arch/mips/include/asm/syscall.h | 32 ++++++++------------------------
 1 file changed, 8 insertions(+), 24 deletions(-)

Comments

Maciej W. Rozycki Feb. 11, 2025, 6:30 p.m. UTC | #1
On Mon, 10 Feb 2025, Dmitry V. Levin wrote:

> The first assertion is fixed for mips o32 by using struct pt_regs.pad0
> instead of get_user() to obtain syscall arguments.  This approach works
> due to this piece in arch/mips/kernel/scall32-o32.S:

 I've had a look now and I can see what's going on here.

 The thing is we're trying to access another task's context and obviously 
dereferencing $sp obtained from it is not going to work via get_user(), 
because that just peeks at the current task's context.  It often does not 
crash, because the default user stack always gets assigned the same VMA, 
but it is pure luck which we wouldn't have if the stack was switched (via 
setcontext(3) or however) or say a non-default process's thread peeked at, 
and in any case irrelevant data is obtained just as observed with the test 
case.

 We ought to be using access_remote_vm() to retrieve the other task's 
stack contents, but given that the data has been already obtained and 
saved in `struct pt_regs' it would be an overkill.

 So I think your change is actually the correct thing to do, but please 
let's not abuse a struct member called `pad', the name of which indicates 
its contents are not supposed to be of any use.  I have therefore posted a 
preparatory cleanup[1].  May you please rebase your patch on top of that 
and also update the change description so as to reflect the findings?

 Thomas, can you please apply my cleanup soon and ahead of Dmitry's change 
so as to make things easy to proceed with?  Or otherwise let me know what 
works for you best.

 Also I have a suspicion this stuff ought to be backported, but I guess it 
can be decided later on.

 Thank you for your patience.

[1] "MIPS: Export syscall stack arguments properly for remote use", 
    <https://lore.kernel.org/linux-mips/alpine.DEB.2.21.2502101732120.65342@angie.orcam.me.uk/>

  Maciej
Dmitry V. Levin Feb. 11, 2025, 10:03 p.m. UTC | #2
On Tue, Feb 11, 2025 at 06:30:33PM +0000, Maciej W. Rozycki wrote:
> On Mon, 10 Feb 2025, Dmitry V. Levin wrote:
> 
> > The first assertion is fixed for mips o32 by using struct pt_regs.pad0
> > instead of get_user() to obtain syscall arguments.  This approach works
> > due to this piece in arch/mips/kernel/scall32-o32.S:
> 
>  I've had a look now and I can see what's going on here.
> 
>  The thing is we're trying to access another task's context and obviously 
> dereferencing $sp obtained from it is not going to work via get_user(), 
> because that just peeks at the current task's context.  It often does not 
> crash, because the default user stack always gets assigned the same VMA, 
> but it is pure luck which we wouldn't have if the stack was switched (via 
> setcontext(3) or however) or say a non-default process's thread peeked at, 
> and in any case irrelevant data is obtained just as observed with the test 
> case.
> 
>  We ought to be using access_remote_vm() to retrieve the other task's 
> stack contents, but given that the data has been already obtained and 
> saved in `struct pt_regs' it would be an overkill.
> 
>  So I think your change is actually the correct thing to do, but please 
> let's not abuse a struct member called `pad', the name of which indicates 
> its contents are not supposed to be of any use.  I have therefore posted a 
> preparatory cleanup[1].  May you please rebase your patch on top of that 
> and also update the change description so as to reflect the findings?
> 
>  Thomas, can you please apply my cleanup soon and ahead of Dmitry's change 
> so as to make things easy to proceed with?  Or otherwise let me know what 
> works for you best.
> 
>  Also I have a suspicion this stuff ought to be backported, but I guess it 
> can be decided later on.
> 
>  Thank you for your patience.
> 
> [1] "MIPS: Export syscall stack arguments properly for remote use", 
>     <https://lore.kernel.org/linux-mips/alpine.DEB.2.21.2502101732120.65342@angie.orcam.me.uk/>

Thanks for the analysis, I'm going to rebase my fix and send it
as a follow-up to your cleanup patch.
diff mbox series

Patch

diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
index ebdf4d910af2..b3f00ede8bb3 100644
--- a/arch/mips/include/asm/syscall.h
+++ b/arch/mips/include/asm/syscall.h
@@ -57,37 +57,21 @@  static inline void mips_syscall_update_nr(struct task_struct *task,
 static inline void mips_get_syscall_arg(unsigned long *arg,
 	struct task_struct *task, struct pt_regs *regs, unsigned int n)
 {
-	unsigned long usp __maybe_unused = regs->regs[29];
-
+#ifdef CONFIG_32BIT
 	switch (n) {
 	case 0: case 1: case 2: case 3:
 		*arg = regs->regs[4 + n];
-
-		return;
-
-#ifdef CONFIG_32BIT
-	case 4: case 5: case 6: case 7:
-		get_user(*arg, (int *)usp + n);
 		return;
-#endif
-
-#ifdef CONFIG_64BIT
 	case 4: case 5: case 6: case 7:
-#ifdef CONFIG_MIPS32_O32
-		if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
-			get_user(*arg, (int *)usp + n);
-		else
-#endif
-			*arg = regs->regs[4 + n];
-
+		*arg = regs->pad0[n];
 		return;
-#endif
-
-	default:
-		BUG();
 	}
-
-	unreachable();
+#else
+	*arg = regs->regs[4 + n];
+	if ((IS_ENABLED(CONFIG_MIPS32_O32) &&
+	     test_tsk_thread_flag(task, TIF_32BIT_REGS)))
+		*arg = (unsigned int)*arg;
+#endif
 }
 
 static inline long syscall_get_error(struct task_struct *task,