Skip to content

Commit 7734a0f

Browse files
alobakinIngo Molnar
authored andcommitted
x86/boot: Robustify calling startup_{32,64}() from the decompressor code
After commit ce697cc ("kbuild: remove head-y syntax"), I started digging whether x86 is ready for removing this old cruft. Removing its objects from the list makes the kernel unbootable. This applies only to bzImage, vmlinux still works correctly. The reason is that with no strict object order determined by the linker arguments, not the linker script, startup_64 can be placed not right at the beginning of the kernel. Here's vmlinux.map's beginning before removing: ffffffff81000000 vmlinux.o:(.head.text) ffffffff81000000 startup_64 ffffffff81000070 secondary_startup_64 ffffffff81000075 secondary_startup_64_no_verify ffffffff81000160 verify_cpu and after: ffffffff81000000 vmlinux.o:(.head.text) ffffffff81000000 pvh_start_xen ffffffff81000080 startup_64 ffffffff810000f0 secondary_startup_64 ffffffff810000f5 secondary_startup_64_no_verify Not a problem itself, but the self-extractor code has the address of that function hardcoded the beginning, not looking onto the ELF header, which always contains the address of startup_{32,64}(). So, instead of doing an "act of blind faith", just take the address from the ELF header and extract a relative offset to the entry point. The decompressor function already returns a pointer to the beginning of the kernel to the Asm code, which then jumps to it, so add that offset to the return value. This doesn't change anything for now, but allows to resign from the "head object list" for x86 and makes sure valid Kbuild or any other improvements won't break anything here in general. Signed-off-by: Alexander Lobakin <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Tested-by: Jiri Slaby <[email protected]> Cc: "H. Peter Anvin" <[email protected]> Cc: Linus Torvalds <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent b7bfaa7 commit 7734a0f

File tree

3 files changed

+13
-9
lines changed

3 files changed

+13
-9
lines changed

arch/x86/boot/compressed/head_32.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
187187
leal boot_heap@GOTOFF(%ebx), %eax
188188
pushl %eax /* heap area */
189189
pushl %esi /* real mode pointer */
190-
call extract_kernel /* returns kernel location in %eax */
190+
call extract_kernel /* returns kernel entry point in %eax */
191191
addl $24, %esp
192192

193193
/*

arch/x86/boot/compressed/head_64.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
569569
movl input_len(%rip), %ecx /* input_len */
570570
movq %rbp, %r8 /* output target address */
571571
movl output_len(%rip), %r9d /* decompressed length, end of relocs */
572-
call extract_kernel /* returns kernel location in %rax */
572+
call extract_kernel /* returns kernel entry point in %rax */
573573
popq %rsi
574574

575575
/*

arch/x86/boot/compressed/misc.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ static inline void handle_relocations(void *output, unsigned long output_len,
277277
{ }
278278
#endif
279279

280-
static void parse_elf(void *output)
280+
static size_t parse_elf(void *output)
281281
{
282282
#ifdef CONFIG_X86_64
283283
Elf64_Ehdr ehdr;
@@ -293,10 +293,8 @@ static void parse_elf(void *output)
293293
if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
294294
ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
295295
ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
296-
ehdr.e_ident[EI_MAG3] != ELFMAG3) {
296+
ehdr.e_ident[EI_MAG3] != ELFMAG3)
297297
error("Kernel is not a valid ELF file");
298-
return;
299-
}
300298

301299
debug_putstr("Parsing ELF... ");
302300

@@ -328,6 +326,8 @@ static void parse_elf(void *output)
328326
}
329327

330328
free(phdrs);
329+
330+
return ehdr.e_entry - LOAD_PHYSICAL_ADDR;
331331
}
332332

333333
/*
@@ -356,6 +356,7 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
356356
const unsigned long kernel_total_size = VO__end - VO__text;
357357
unsigned long virt_addr = LOAD_PHYSICAL_ADDR;
358358
unsigned long needed_size;
359+
size_t entry_offset;
359360

360361
/* Retain x86 boot parameters pointer passed from startup_32/64. */
361362
boot_params = rmode;
@@ -456,14 +457,17 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
456457
debug_putstr("\nDecompressing Linux... ");
457458
__decompress(input_data, input_len, NULL, NULL, output, output_len,
458459
NULL, error);
459-
parse_elf(output);
460+
entry_offset = parse_elf(output);
460461
handle_relocations(output, output_len, virt_addr);
461-
debug_putstr("done.\nBooting the kernel.\n");
462+
463+
debug_putstr("done.\nBooting the kernel (entry_offset: 0x");
464+
debug_puthex(entry_offset);
465+
debug_putstr(").\n");
462466

463467
/* Disable exception handling before booting the kernel */
464468
cleanup_exception_handling();
465469

466-
return output;
470+
return output + entry_offset;
467471
}
468472

469473
void fortify_panic(const char *name)

0 commit comments

Comments
 (0)