]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
sh: reload r3 after arg evaluation in INTERNAL_SYSCALL [BZ #34167]
authorMatt Turner <mattst88@gmail.com>
Sat, 23 May 2026 20:18:27 +0000 (16:18 -0400)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Mon, 25 May 2026 13:50:54 +0000 (13:50 +0000)
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 <adhemerval.zanella@linaro.org>
sysdeps/unix/sysv/linux/sh/sysdep.h

index d51988e5b0230d8b31ebb019f53fee169d1eb058..1562213bf6f026db93498101e1456fa54ab7d8bc 100644 (file)
 #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)                                          \
 #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)                                          \