diff options
author | Jens Remus <jremus@linux.ibm.com> | 2024-06-20 11:12:49 +0200 |
---|---|---|
committer | Alexander Gordeev <agordeev@linux.ibm.com> | 2024-06-25 14:39:42 +0200 |
commit | cea5589e958f8aef301ce9d004bc73fa5bb3b304 (patch) | |
tree | b5c3bb347a5d7595b6cd41a3afea183bbb4b1124 /arch/s390/boot | |
parent | s390/sclp: Fix sclp_init() cleanup on failure (diff) | |
download | linux-cea5589e958f8aef301ce9d004bc73fa5bb3b304.tar.xz linux-cea5589e958f8aef301ce9d004bc73fa5bb3b304.zip |
s390/boot: Do not adjust GOT entries for undef weak sym
Since commit 778666df60f0 ("s390: compile relocatable kernel without
-fPIE") and commit 00cda11d3b2e ("s390: Compile kernel with -fPIC and
link with -no-pie") the kernel on s390x may have a Global Offset Table
(GOT) whose entries are adjusted for KASLR in kaslr_adjust_got().
The GOT may contain entries for undefined weak symbols that resolved to
zero. That is the resulting GOT entry value is zero. Adjusting those
entries unconditionally in kaslr_adjust_got() is wrong. Otherwise the
following sample code would erroneously assume foo to be defined, due to
the adjustment changing the zero-value to a non-zero one:
extern int foo __attribute__((weak));
if (*foo)
/* foo is defined [or undefined and erroneously adjusted] */
The vmlinux build at commit 00cda11d3b2e ("s390: Compile kernel with
-fPIC and link with -no-pie") with defconfig actually had two GOT
entries for the undefined weak symbols __start_BTF and __stop_BTF:
$ objdump -tw vmlinux | grep -F "*UND*"
0000000000000000 w *UND* 0000000000000000 __stop_BTF
0000000000000000 w *UND* 0000000000000000 __start_BTF
$ readelf -rw vmlinux | grep -E "R_390_GOTENT +0{16}"
000000345760 2776a0000001a R_390_GOTENT 0000000000000000 __stop_BTF + 2
000000345766 2d5480000001a R_390_GOTENT 0000000000000000 __start_BTF + 2
The s390-specific vmlinux linker script sets the section start to
__START_KERNEL, which is currently defined as 0x100000 on s390x. Access
to lowcore is performed via a pointer of 0 and not a symbol in a section
starting at 0. The first 64K are reserved for the loader on s390x. Thus
it is safe to assume that __START_KERNEL will never be 0. As a result
there cannot be any defined symbols resolving to zero in the kernel.
Note that the first three GOT entries are reserved for the dynamic
loader on s390x. [1] In the kernel they are zero. Therefore no extra
handling is required to skip these.
Skip adjusting GOT entries with a value of zero in kaslr_adjust_got().
While at it update the comment when a GOT exists on s390x. Since commit
00cda11d3b2e ("s390: Compile kernel with -fPIC and link with -no-pie")
it no longer only exists when compiling with Clang, but also with GCC.
[1]: s390x ELF ABI, section "Global Offset Table",
https://github.com/IBM/s390x-abi/releases
Fixes: 778666df60f0 ("s390: compile relocatable kernel without -fPIE")
Reviewed-by: Ilya Leoshkevich <iii@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
Diffstat (limited to 'arch/s390/boot')
-rw-r--r-- | arch/s390/boot/startup.c | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index 48ef5fe5c08a..5a36d5538dae 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c @@ -170,11 +170,14 @@ static void kaslr_adjust_got(unsigned long offset) u64 *entry; /* - * Even without -fPIE, Clang still uses a global offset table for some - * reason. Adjust the GOT entries. + * Adjust GOT entries, except for ones for undefined weak symbols + * that resolved to zero. This also skips the first three reserved + * entries on s390x that are zero. */ - for (entry = (u64 *)vmlinux.got_start; entry < (u64 *)vmlinux.got_end; entry++) - *entry += offset - __START_KERNEL; + for (entry = (u64 *)vmlinux.got_start; entry < (u64 *)vmlinux.got_end; entry++) { + if (*entry) + *entry += offset - __START_KERNEL; + } } /* |