From: Matt Turner Date: Sat, 23 May 2026 20:18:27 +0000 (-0400) Subject: sh: reload r3 after arg evaluation in INTERNAL_SYSCALL [BZ #34167] X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=b0f985a21eb55ae9ee3200efabd802aa24744477;p=thirdparty%2Fglibc.git sh: reload r3 after arg evaluation in INTERNAL_SYSCALL [BZ #34167] r3 is caller-saved. When a function call appears in the args list (e.g. INTERNAL_SYSCALL_CALL(tgkill, __getpid(), tid, sig)), SUBSTITUTE_ARGS evaluates __getpid() before r3 is reloaded, leaving r3=20 (__NR_getpid) instead of __NR_tgkill=270. The trapa then dispatches the wrong syscall and the signal is silently dropped. Fix: declare r3 uninitialised, expand SUBSTITUTE_ARGS (all function calls happen here), then assign the syscall number to r3 with no intervening calls before the trapa. Applies to both INTERNAL_SYSCALL and INTERNAL_SYSCALL_NCS. signal/tst-raise is a regression test for this bug: raise() calls tgkill(__getpid(), tid, sig), which triggers the clobber. Reviewed-by: Adhemerval Zanella --- diff --git a/sysdeps/unix/sysv/linux/sh/sysdep.h b/sysdeps/unix/sysv/linux/sh/sysdep.h index d51988e5b0..1562213bf6 100644 --- a/sysdeps/unix/sysv/linux/sh/sysdep.h +++ b/sysdeps/unix/sysv/linux/sh/sysdep.h @@ -289,8 +289,9 @@ #define INTERNAL_SYSCALL(name, nr, args...) \ ({ \ unsigned long int resultvar; \ - register long int r3 asm ("%r3") = SYS_ify (name); \ + register long int r3 asm ("%r3"); \ SUBSTITUTE_ARGS_##nr(args); \ + r3 = SYS_ify (name); \ \ asm volatile (SYSCALL_INST_STR##nr SYSCALL_INST_PAD \ : "=z" (resultvar) \ @@ -303,8 +304,9 @@ #define INTERNAL_SYSCALL_NCS(name, nr, args...) \ ({ \ unsigned long int resultvar; \ - register long int r3 asm ("%r3") = (name); \ + register long int r3 asm ("%r3"); \ SUBSTITUTE_ARGS_##nr(args); \ + r3 = (name); \ \ asm volatile (SYSCALL_INST_STR##nr SYSCALL_INST_PAD \ : "=z" (resultvar) \