x86/boot: Remove run-time relocations from head_{32,64}.S
authorArvind Sankar <nivedita@alum.mit.edu>
Fri, 31 Jul 2020 23:07:50 +0000 (16:07 -0700)
committerIngo Molnar <mingo@kernel.org>
Fri, 14 Aug 2020 10:52:35 +0000 (12:52 +0200)
The BFD linker generates run-time relocations for z_input_len and
z_output_len, even though they are absolute symbols.

This is fixed for binutils-2.35 [1]. Work around this for earlier
versions by defining two variables input_len and output_len in addition
to the symbols, and use them via position-independent references.

This eliminates the last two run-time relocations in the head code and
allows us to drop the -z noreloc-overflow flag to the linker.

Move the -pie and --no-dynamic-linker LDFLAGS to LDFLAGS_vmlinux instead
of KBUILD_LDFLAGS. There shouldn't be anything else getting linked, but
this is the more logical location for these flags, and modversions might
call the linker if an EXPORT_SYMBOL is left over accidentally in one of
the decompressors.

[1] https://sourceware.org/bugzilla/show_bug.cgi?id=25754

Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Tested-by: Nick Desaulniers <ndesaulniers@google.com>
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Fangrui Song <maskray@google.com>
Link: https://lore.kernel.org/r/20200731230820.1742553-7-keescook@chromium.org
arch/x86/boot/compressed/Makefile
arch/x86/boot/compressed/head_32.S
arch/x86/boot/compressed/head_64.S
arch/x86/boot/compressed/mkpiggy.c

index 7c687a7..7d25089 100644 (file)
@@ -52,16 +52,8 @@ UBSAN_SANITIZE :=n
 KBUILD_LDFLAGS := -m elf_$(UTS_MACHINE)
 # Compressed kernel should be built as PIE since it may be loaded at any
 # address by the bootloader.
-ifeq ($(CONFIG_X86_32),y)
-KBUILD_LDFLAGS += $(call ld-option, -pie) $(call ld-option, --no-dynamic-linker)
-else
-# To build 64-bit compressed kernel as PIE, we disable relocation
-# overflow check to avoid relocation overflow error with a new linker
-# command-line option, -z noreloc-overflow.
-KBUILD_LDFLAGS += $(shell $(LD) --help 2>&1 | grep -q "\-z noreloc-overflow" \
-       && echo "-z noreloc-overflow -pie --no-dynamic-linker")
-endif
-LDFLAGS_vmlinux := -T
+LDFLAGS_vmlinux := $(call ld-option, -pie) $(call ld-option, --no-dynamic-linker)
+LDFLAGS_vmlinux += -T
 
 hostprogs      := mkpiggy
 HOST_EXTRACFLAGS += -I$(srctree)/tools/include
index 8c1a4f5..659fad5 100644 (file)
@@ -178,18 +178,17 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
 /*
  * Do the extraction, and jump to the new kernel..
  */
-                               /* push arguments for extract_kernel: */
-       pushl   $z_output_len   /* decompressed length, end of relocs */
+       /* push arguments for extract_kernel: */
 
-       pushl   %ebp            /* output address */
-
-       pushl   $z_input_len    /* input_len */
+       pushl   output_len@GOTOFF(%ebx) /* decompressed length, end of relocs */
+       pushl   %ebp                    /* output address */
+       pushl   input_len@GOTOFF(%ebx)  /* input_len */
        leal    input_data@GOTOFF(%ebx), %eax
-       pushl   %eax            /* input_data */
+       pushl   %eax                    /* input_data */
        leal    boot_heap@GOTOFF(%ebx), %eax
-       pushl   %eax            /* heap area */
-       pushl   %esi            /* real mode pointer */
-       call    extract_kernel  /* returns kernel location in %eax */
+       pushl   %eax                    /* heap area */
+       pushl   %esi                    /* real mode pointer */
+       call    extract_kernel          /* returns kernel location in %eax */
        addl    $24, %esp
 
 /*
index 1142909..9e46729 100644 (file)
@@ -534,9 +534,9 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
        movq    %rsi, %rdi              /* real mode address */
        leaq    boot_heap(%rip), %rsi   /* malloc area for uncompression */
        leaq    input_data(%rip), %rdx  /* input_data */
-       movl    $z_input_len, %ecx      /* input_len */
+       movl    input_len(%rip), %ecx   /* input_len */
        movq    %rbp, %r8               /* output target address */
-       movl    $z_output_len, %r9d     /* decompressed length, end of relocs */
+       movl    output_len(%rip), %r9d  /* decompressed length, end of relocs */
        call    extract_kernel          /* returns kernel location in %rax */
        popq    %rsi
 
index 7e01248..52aa56c 100644 (file)
@@ -60,6 +60,12 @@ int main(int argc, char *argv[])
        printf(".incbin \"%s\"\n", argv[1]);
        printf("input_data_end:\n");
 
+       printf(".section \".rodata\",\"a\",@progbits\n");
+       printf(".globl input_len\n");
+       printf("input_len:\n\t.long %lu\n", ilen);
+       printf(".globl output_len\n");
+       printf("output_len:\n\t.long %lu\n", (unsigned long)olen);
+
        retval = 0;
 bail:
        if (f)