Skip to content

Commit 5214028

Browse files
nivedita76suryasaimadhu
authored andcommitted
x86/boot: Correct relocation destination on old linkers
For the 32-bit kernel, as described in 6d92bc9 ("x86/build: Build compressed x86 kernels as PIE"), pre-2.26 binutils generates R_386_32 relocations in PIE mode. Since the startup code does not perform relocation, any reloc entry with R_386_32 will remain as 0 in the executing code. Commit 974f221 ("x86/boot: Move compressed kernel to the end of the decompression buffer") added a new symbol _end but did not mark it hidden, which doesn't give the correct offset on older linkers. This causes the compressed kernel to be copied beyond the end of the decompression buffer, rather than flush against it. This region of memory may be reserved or already allocated for other purposes by the bootloader. Mark _end as hidden to fix. This changes the relocation from R_386_32 to R_386_RELATIVE even on the pre-2.26 binutils. For 64-bit, this is not strictly necessary, as the 64-bit kernel is only built as PIE if the linker supports -z noreloc-overflow, which implies binutils-2.27+, but for consistency, mark _end as hidden here too. The below illustrates the before/after impact of the patch using binutils-2.25 and gcc-4.6.4 (locally compiled from source) and QEMU. Disassembly before patch: 48: 8b 86 60 02 00 00 mov 0x260(%esi),%eax 4e: 2d 00 00 00 00 sub $0x0,%eax 4f: R_386_32 _end Disassembly after patch: 48: 8b 86 60 02 00 00 mov 0x260(%esi),%eax 4e: 2d 00 f0 76 00 sub $0x76f000,%eax 4f: R_386_RELATIVE *ABS* Dump from extract_kernel before patch: early console in extract_kernel input_data: 0x0207c098 <--- this is at output + init_size input_len: 0x0074fef1 output: 0x01000000 output_len: 0x00fa63d0 kernel_total_size: 0x0107c000 needed_size: 0x0107c000 Dump from extract_kernel after patch: early console in extract_kernel input_data: 0x0190d098 <--- this is at output + init_size - _end input_len: 0x0074fef1 output: 0x01000000 output_len: 0x00fa63d0 kernel_total_size: 0x0107c000 needed_size: 0x0107c000 Fixes: 974f221 ("x86/boot: Move compressed kernel to the end of the decompression buffer") Signed-off-by: Arvind Sankar <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 34bb492 commit 5214028

File tree

2 files changed

+4
-2
lines changed

2 files changed

+4
-2
lines changed

arch/x86/boot/compressed/head_32.S

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,17 @@
4949
* Position Independent Executable (PIE) so that linker won't optimize
5050
* R_386_GOT32X relocation to its fixed symbol address. Older
5151
* linkers generate R_386_32 relocations against locally defined symbols,
52-
* _bss, _ebss, _got and _egot, in PIE. It isn't wrong, just less
52+
* _bss, _ebss, _got, _egot and _end, in PIE. It isn't wrong, just less
5353
* optimal than R_386_RELATIVE. But the x86 kernel fails to properly handle
5454
* R_386_32 relocations when relocating the kernel. To generate
55-
* R_386_RELATIVE relocations, we mark _bss, _ebss, _got and _egot as
55+
* R_386_RELATIVE relocations, we mark _bss, _ebss, _got, _egot and _end as
5656
* hidden:
5757
*/
5858
.hidden _bss
5959
.hidden _ebss
6060
.hidden _got
6161
.hidden _egot
62+
.hidden _end
6263

6364
__HEAD
6465
SYM_FUNC_START(startup_32)

arch/x86/boot/compressed/head_64.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
.hidden _ebss
4343
.hidden _got
4444
.hidden _egot
45+
.hidden _end
4546

4647
__HEAD
4748
.code32

0 commit comments

Comments
 (0)