[PATCH] s390: Prevent hoisting the thread-pointer read in THREAD_SET_STACK_GUARD (BZ 34297)
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Mon Jul 6 12:53:06 GMT 2026
On 06/07/26 09:50, Stefan Liebler wrote:
> On 6/17/26 16:25, Adhemerval Zanella wrote:
>> THREAD_SET_STACK_GUARD reads the thread pointer via THREAD_SELF
>> (__builtin_thread_pointer), which the compiler treats as invariant. In the
>> static startup path the thread pointer is installed by the __libc_setup_tls
>> call that immediately precedes the guard store, so the read must stay below
>> it. The existing barrier only clobbered the access registers a0/a1, which
>> creates no dependency on the call, so the compiler could move the whole
>> barrier and read above __libc_setup_tls.
>>
>> This is sensitive to instruction scheduling and recent TLS startup
>> changes exposed it on s390x.
>>
>> Add a "memory" clobber to the barrier so it is tied to the call's memory
>> effects and cannot be hoisted above it. The macro is shared with the
>> dynamic loader, so both startup paths are covered.
>>
>> I checked on s390x-linux-gnu build for arch5, arch8, arch9, and arch11
>> byt running the elf tests on qemu system (kernel 6.1.0).
>> ---
>> sysdeps/s390/nptl/tls.h | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/sysdeps/s390/nptl/tls.h b/sysdeps/s390/nptl/tls.h
>> index 41fd473d14a..6ecaa243841 100644
>> --- a/sysdeps/s390/nptl/tls.h
>> +++ b/sysdeps/s390/nptl/tls.h
>> @@ -131,7 +131,7 @@ typedef struct
>> #define THREAD_SET_STACK_GUARD(value) \
>> do \
>> { \
>> - __asm__ __volatile__ ("" : : : "a0", "a1"); \
>> + __asm__ __volatile__ ("" : : : "a0", "a1", "memory"); \
>> THREAD_SETMEM (THREAD_SELF, header.stack_guard, value); \
>> } \
>> while (0)
>
> Hi Adhemerval,
>
> sorry for the long delay. I was away quite away for a while.
>
> I can confirm, that without the patch for a static binary, reading a0 is
> moved before the __libc_setup_tls call where a0/a1 is set up to the
> valid thread pointer.
>
> With the additional memory barrier, the reading of a0 takes place after
> __libc_setup_tls.
>
> I've also tested this patch with various configurations.
>
> Reviewed-by: Stefan Liebler <stli@linux.ibm.com>
Thanks.
>
>
>
> Independent of this patch, I've recognized that e.g. the new static test
> elf/tst-ptrguard-static-dlopen can fail as test-container may fail to
> start due to wrong GLIBC_2.XY version of system libc.so symbols. Usually
> test-via-rtld-prefix is set to run-via-rtld-prefix in Makeconfig. The
> latter one is set to "../ld.so --library-path ..." for dynamic tests,
> but not for those listed in tests-static. In this case, the test itself
> is static, but test-container is dynamically linked and is run without
> "../ld.so --library-path ...".
Yes, Sachin has already brought this up and master should have this fixed [1].
[1] https://sourceware.org/git/?p=glibc.git;a=commit;h=1ab000387207a968f7cd18a5f3e3e7dcdadad139
More information about the Libc-alpha
mailing list