• Arvind Sankar's avatar
    x86/boot: Remove run-time relocations from .head.text code · a2c4fc4d
    Arvind Sankar authored
    The assembly code in head_{32,64}.S, while meant to be
    position-independent, generates run-time relocations because it uses
    instructions such as:
    
    	leal	gdt(%edx), %eax
    
    which make the assembler and linker think that the code is using %edx as
    an index into gdt, and hence gdt needs to be relocated to its run-time
    address.
    
    On 32-bit, with lld Dmitry Golovin reports that this results in a
    link-time error with default options (i.e. unless -z notext is
    explicitly passed):
    
      LD      arch/x86/boot/compressed/vmlinux
      ld.lld: error: can't create dynamic relocation R_386_32 against local
      symbol in readonly segment; recompile object files with -fPIC or pass
      '-Wl,-z,notext' to allow text relocations in the output
    
    With the BFD linker, this generates a warning during the build, if
    --warn-shared-textrel is enabled, which at least Gentoo enables by
    default:
    
      LD      arch/x86/boot/compressed/vmlinux
      ld: arch/x86/boot/compressed/head_32.o: warning: relocation in read-only section `.head.text'
      ld: warning: creating a DT_TEXTREL in object
    
    On 64-bit, it is not possible to link the kernel as -pie with lld, and
    it is only possible with a BFD linker that supports -z noreloc-overflow,
    i.e. versions >2.26. This is because these instructions cannot really be
    relocated: the displacement field is only 32-bits wide, and thus cannot
    be relocated for a 64-bit load address. The -z noreloc-overflow option
    simply overrides the linker error, and results in R_X86_64_RELATIVE
    relocations that apply a 64-bit relocation to a 32-bit field anyway.
    This happens to work because nothing will process these run-time
    relocations.
    
    Start fixing this by removing relocations from .head.text:
    
    - On 32-bit, use a base register that holds the address of the GOT and
      reference symbol addresses using @GOTOFF, i.e.
    	leal	gdt@GOTOFF(%edx), %eax
    
    - On 64-bit, most of the code can (and already does) use %rip-relative
      addressing, however the .code32 bits can't, and the 64-bit code also
      needs to reference symbol addresses as they will be after moving the
      compressed kernel to the end of the decompression buffer.
      For these cases, reference the symbols as an offset to startup_32 to
      avoid creating relocations, i.e.:
    
    	leal	(gdt-startup_32)(%bp), %eax
    
      This only works in .head.text as the subtraction cannot be represented
      as a PC-relative relocation unless startup_32 is in the same section
      as the code. Move efi32_pe_entry into .head.text so that it can use
      the same method to avoid relocations.
    Reported-by: default avatarDmitry Golovin <dima@golovin.in>
    Signed-off-by: default avatarArvind Sankar <nivedita@alum.mit.edu>
    Signed-off-by: default avatarKees Cook <keescook@chromium.org>
    Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
    Tested-by: default avatarNick Desaulniers <ndesaulniers@google.com>
    Tested-by: default avatarSedat Dilek <sedat.dilek@gmail.com>
    Reviewed-by: default avatarKees Cook <keescook@chromium.org>
    Reviewed-by: default avatarArd Biesheuvel <ardb@kernel.org>
    Reviewed-by: default avatarFangrui Song <maskray@google.com>
    Link: https://lore.kernel.org/r/20200731230820.1742553-6-keescook@chromium.org
    a2c4fc4d
head_64.S 20.2 KB