From 262b5cae67a672404da0dcbd009efc1227ad51e4 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 31 Jul 2020 16:07:45 -0700 Subject: [PATCH 01/36] x86/boot/compressed: Move .got.plt entries out of the .got section The .got.plt section contains the part of the GOT which is used by PLT entries, and which gets updated lazily by the dynamic loader when function calls are dispatched through those PLT entries. On fully linked binaries such as the kernel proper or the decompressor, this never happens, and so in practice, the .got.plt section consists only of the first 3 magic entries that are meant to point at the _DYNAMIC section and at the fixup routine in the loader. However, since we don't use a dynamic loader, those entries are never populated or used. This means that treating those entries like ordinary GOT entries, and updating their values based on the actual placement of the executable in memory is completely pointless, and we can just ignore the .got.plt section entirely, provided that it has no additional entries beyond the first 3 ones. So add an assertion in the linker script to ensure that this assumption holds, and move the contents out of the [_got, _egot) memory range that is modified by the GOT fixup routines. While at it, drop the KEEP(), since it has no effect on the contents of output sections that are created by the linker itself. Signed-off-by: Ard Biesheuvel Signed-off-by: Arvind Sankar Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Tested-by: Sedat Dilek Tested-by: Nick Desaulniers Reviewed-by: Kees Cook Acked-by: Arvind Sankar Link: https://lore.kernel.org/r/20200731230820.1742553-2-keescook@chromium.org --- arch/x86/boot/compressed/vmlinux.lds.S | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S index 8f1025d1f681..b17d218ccdf9 100644 --- a/arch/x86/boot/compressed/vmlinux.lds.S +++ b/arch/x86/boot/compressed/vmlinux.lds.S @@ -44,10 +44,13 @@ SECTIONS } .got : { _got = .; - KEEP(*(.got.plt)) KEEP(*(.got)) _egot = .; } + .got.plt : { + *(.got.plt) + } + .data : { _data = . ; *(.data) @@ -77,3 +80,9 @@ SECTIONS DISCARDS } + +#ifdef CONFIG_X86_64 +ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18, "Unexpected GOT/PLT entries detected!") +#else +ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0xc, "Unexpected GOT/PLT entries detected!") +#endif From e544ea57ac0734bca752eb2d8635fecbe932c356 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 31 Jul 2020 16:07:46 -0700 Subject: [PATCH 02/36] x86/boot/compressed: Force hidden visibility for all symbol references Eliminate all GOT entries in the decompressor binary, by forcing hidden visibility for all symbol references, which informs the compiler that such references will be resolved at link time without the need for allocating GOT entries. To ensure that no GOT entries will creep back in, add an assertion to the decompressor linker script that will fire if the .got section has a non-zero size. [Arvind: move hidden.h to include/linux instead of making a copy] Signed-off-by: Ard Biesheuvel Signed-off-by: Arvind Sankar Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Tested-by: Nick Desaulniers Tested-by: Sedat Dilek Reviewed-by: Kees Cook Acked-by: Arvind Sankar Link: https://lore.kernel.org/r/20200731230820.1742553-3-keescook@chromium.org --- arch/x86/boot/compressed/Makefile | 1 + arch/x86/boot/compressed/vmlinux.lds.S | 1 + drivers/firmware/efi/libstub/Makefile | 2 +- drivers/firmware/efi/libstub/hidden.h | 6 ------ include/linux/hidden.h | 19 +++++++++++++++++++ 5 files changed, 22 insertions(+), 7 deletions(-) delete mode 100644 drivers/firmware/efi/libstub/hidden.h create mode 100644 include/linux/hidden.h diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 3962f592633d..7c687a770537 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -43,6 +43,7 @@ KBUILD_CFLAGS += -Wno-pointer-sign KBUILD_CFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=) KBUILD_CFLAGS += -fno-asynchronous-unwind-tables KBUILD_CFLAGS += -D__DISABLE_EXPORTS +KBUILD_CFLAGS += -include $(srctree)/include/linux/hidden.h KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ GCOV_PROFILE := n diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S index b17d218ccdf9..4bcc943842ab 100644 --- a/arch/x86/boot/compressed/vmlinux.lds.S +++ b/arch/x86/boot/compressed/vmlinux.lds.S @@ -81,6 +81,7 @@ SECTIONS DISCARDS } +ASSERT(SIZEOF(.got) == 0, "Unexpected GOT entries detected!") #ifdef CONFIG_X86_64 ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18, "Unexpected GOT/PLT entries detected!") #else diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 296b18fbd7a2..5eefd60917df 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -26,7 +26,7 @@ cflags-$(CONFIG_ARM) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \ cflags-$(CONFIG_EFI_GENERIC_STUB) += -I$(srctree)/scripts/dtc/libfdt KBUILD_CFLAGS := $(cflags-y) -Os -DDISABLE_BRANCH_PROFILING \ - -include $(srctree)/drivers/firmware/efi/libstub/hidden.h \ + -include $(srctree)/include/linux/hidden.h \ -D__NO_FORTIFY \ -ffreestanding \ -fno-stack-protector \ diff --git a/drivers/firmware/efi/libstub/hidden.h b/drivers/firmware/efi/libstub/hidden.h deleted file mode 100644 index 3493b041f419..000000000000 --- a/drivers/firmware/efi/libstub/hidden.h +++ /dev/null @@ -1,6 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * To prevent the compiler from emitting GOT-indirected (and thus absolute) - * references to any global symbols, override their visibility as 'hidden' - */ -#pragma GCC visibility push(hidden) diff --git a/include/linux/hidden.h b/include/linux/hidden.h new file mode 100644 index 000000000000..49a17b6b5962 --- /dev/null +++ b/include/linux/hidden.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * When building position independent code with GCC using the -fPIC option, + * (or even the -fPIE one on older versions), it will assume that we are + * building a dynamic object (either a shared library or an executable) that + * may have symbol references that can only be resolved at load time. For a + * variety of reasons (ELF symbol preemption, the CoW footprint of the section + * that is modified by the loader), this results in all references to symbols + * with external linkage to go via entries in the Global Offset Table (GOT), + * which carries absolute addresses which need to be fixed up when the + * executable image is loaded at an offset which is different from its link + * time offset. + * + * Fortunately, there is a way to inform the compiler that such symbol + * references will be satisfied at link time rather than at load time, by + * giving them 'hidden' visibility. + */ + +#pragma GCC visibility push(hidden) From 423e4d198a036689de73fd6b073fc4349c4fa1ee Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 31 Jul 2020 16:07:47 -0700 Subject: [PATCH 03/36] x86/boot/compressed: Get rid of GOT fixup code In a previous patch, we have eliminated GOT entries from the decompressor binary and added an assertion that the .got section is empty. This means that the GOT fixup routines that exist in both the 32-bit and 64-bit startup routines have become dead code, and can be removed. While at it, drop the KEEP() from the linker script, as it has no effect on the contents of output sections that are created by the linker itself. Signed-off-by: Ard Biesheuvel Signed-off-by: Arvind Sankar Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Tested-by: Nick Desaulniers Tested-by: Sedat Dilek Reviewed-by: Kees Cook Acked-by: Arvind Sankar Link: https://lore.kernel.org/r/20200731230820.1742553-4-keescook@chromium.org --- arch/x86/boot/compressed/head_32.S | 24 ++--------- arch/x86/boot/compressed/head_64.S | 57 -------------------------- arch/x86/boot/compressed/vmlinux.lds.S | 4 +- 3 files changed, 5 insertions(+), 80 deletions(-) diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index 03557f2174bf..39f0bb43218f 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -49,16 +49,13 @@ * Position Independent Executable (PIE) so that linker won't optimize * R_386_GOT32X relocation to its fixed symbol address. Older * linkers generate R_386_32 relocations against locally defined symbols, - * _bss, _ebss, _got, _egot and _end, in PIE. It isn't wrong, just less - * optimal than R_386_RELATIVE. But the x86 kernel fails to properly handle - * R_386_32 relocations when relocating the kernel. To generate - * R_386_RELATIVE relocations, we mark _bss, _ebss, _got, _egot and _end as - * hidden: + * _bss, _ebss and _end, in PIE. It isn't wrong, just less optimal than + * R_386_RELATIVE. But the x86 kernel fails to properly handle R_386_32 + * relocations when relocating the kernel. To generate R_386_RELATIVE + * relocations, we mark _bss, _ebss and _end as hidden: */ .hidden _bss .hidden _ebss - .hidden _got - .hidden _egot .hidden _end __HEAD @@ -192,19 +189,6 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated) shrl $2, %ecx rep stosl -/* - * Adjust our own GOT - */ - leal _got(%ebx), %edx - leal _egot(%ebx), %ecx -1: - cmpl %ecx, %edx - jae 2f - addl %ebx, (%edx) - addl $4, %edx - jmp 1b -2: - /* * Do the extraction, and jump to the new kernel.. */ diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index 97d37f0a34f5..bf1ab30acc5b 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -40,8 +40,6 @@ */ .hidden _bss .hidden _ebss - .hidden _got - .hidden _egot .hidden _end __HEAD @@ -353,25 +351,6 @@ SYM_CODE_START(startup_64) /* Set up the stack */ leaq boot_stack_end(%rbx), %rsp - /* - * paging_prepare() and cleanup_trampoline() below can have GOT - * references. Adjust the table with address we are running at. - * - * Zero RAX for adjust_got: the GOT was not adjusted before; - * there's no adjustment to undo. - */ - xorq %rax, %rax - - /* - * Calculate the address the binary is loaded at and use it as - * a GOT adjustment. - */ - call 1f -1: popq %rdi - subq $1b, %rdi - - call .Ladjust_got - /* * At this point we are in long mode with 4-level paging enabled, * but we might want to enable 5-level paging or vice versa. @@ -464,21 +443,6 @@ trampoline_return: pushq $0 popfq - /* - * Previously we've adjusted the GOT with address the binary was - * loaded at. Now we need to re-adjust for relocation address. - * - * Calculate the address the binary is loaded at, so that we can - * undo the previous GOT adjustment. - */ - call 1f -1: popq %rax - subq $1b, %rax - - /* The new adjustment is the relocation address */ - movq %rbx, %rdi - call .Ladjust_got - /* * Copy the compressed kernel to the end of our buffer * where decompression in place becomes safe. @@ -556,27 +520,6 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated) jmp *%rax SYM_FUNC_END(.Lrelocated) -/* - * Adjust the global offset table - * - * RAX is the previous adjustment of the table to undo (use 0 if it's the - * first time we touch GOT). - * RDI is the new adjustment to apply. - */ -.Ladjust_got: - /* Walk through the GOT adding the address to the entries */ - leaq _got(%rip), %rdx - leaq _egot(%rip), %rcx -1: - cmpq %rcx, %rdx - jae 2f - subq %rax, (%rdx) /* Undo previous adjustment */ - addq %rdi, (%rdx) /* Apply the new adjustment */ - addq $8, %rdx - jmp 1b -2: - ret - .code32 /* * This is the 32-bit trampoline that will be copied over to low memory. diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S index 4bcc943842ab..a4a4a59a2628 100644 --- a/arch/x86/boot/compressed/vmlinux.lds.S +++ b/arch/x86/boot/compressed/vmlinux.lds.S @@ -43,9 +43,7 @@ SECTIONS _erodata = . ; } .got : { - _got = .; - KEEP(*(.got)) - _egot = .; + *(.got) } .got.plt : { *(.got.plt) From 2e7a858ba843d2e6ceab1ba996805411de51b340 Mon Sep 17 00:00:00 2001 From: Arvind Sankar Date: Fri, 31 Jul 2020 16:07:48 -0700 Subject: [PATCH 04/36] x86/boot: Add .text.* to setup.ld GCC puts the main function into .text.startup when compiled with -Os (or -O2). This results in arch/x86/boot/main.c having a .text.startup section which is currently not included explicitly in the linker script setup.ld in the same directory. The BFD linker places this orphan section immediately after .text, so this still works. However, LLD git, since [1], is choosing to place it immediately after the .bstext section instead (this is the first code section). This plays havoc with the section layout that setup.elf requires to create the setup header, for eg on 64-bit: LD arch/x86/boot/setup.elf ld.lld: error: section .text.startup file range overlaps with .header >>> .text.startup range is [0x200040, 0x2001FE] >>> .header range is [0x2001EF, 0x20026B] ld.lld: error: section .header file range overlaps with .bsdata >>> .header range is [0x2001EF, 0x20026B] >>> .bsdata range is [0x2001FF, 0x200398] ld.lld: error: section .bsdata file range overlaps with .entrytext >>> .bsdata range is [0x2001FF, 0x200398] >>> .entrytext range is [0x20026C, 0x2002D3] ld.lld: error: section .text.startup virtual address range overlaps with .header >>> .text.startup range is [0x40, 0x1FE] >>> .header range is [0x1EF, 0x26B] ld.lld: error: section .header virtual address range overlaps with .bsdata >>> .header range is [0x1EF, 0x26B] >>> .bsdata range is [0x1FF, 0x398] ld.lld: error: section .bsdata virtual address range overlaps with .entrytext >>> .bsdata range is [0x1FF, 0x398] >>> .entrytext range is [0x26C, 0x2D3] ld.lld: error: section .text.startup load address range overlaps with .header >>> .text.startup range is [0x40, 0x1FE] >>> .header range is [0x1EF, 0x26B] ld.lld: error: section .header load address range overlaps with .bsdata >>> .header range is [0x1EF, 0x26B] >>> .bsdata range is [0x1FF, 0x398] ld.lld: error: section .bsdata load address range overlaps with .entrytext >>> .bsdata range is [0x1FF, 0x398] >>> .entrytext range is [0x26C, 0x2D3] Add .text.* to the .text output section to fix this, and also prevent any future surprises if the compiler decides to create other such sections. [1] https://reviews.llvm.org/D75225 Signed-off-by: Arvind Sankar Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Tested-by: Nick Desaulniers Tested-by: Sedat Dilek Reviewed-by: Kees Cook Reviewed-by: Ard Biesheuvel Reviewed-by: Fangrui Song Link: https://lore.kernel.org/r/20200731230820.1742553-5-keescook@chromium.org --- arch/x86/boot/setup.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/boot/setup.ld b/arch/x86/boot/setup.ld index 24c95522f231..49546c247ae2 100644 --- a/arch/x86/boot/setup.ld +++ b/arch/x86/boot/setup.ld @@ -20,7 +20,7 @@ SECTIONS .initdata : { *(.initdata) } __end_init = .; - .text : { *(.text) } + .text : { *(.text .text.*) } .text32 : { *(.text32) } . = ALIGN(16); From a2c4fc4d4e2c40b07534094810d915c7354d84a7 Mon Sep 17 00:00:00 2001 From: Arvind Sankar Date: Fri, 31 Jul 2020 16:07:49 -0700 Subject: [PATCH 05/36] x86/boot: Remove run-time relocations from .head.text code 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: Dmitry Golovin Signed-off-by: Arvind Sankar Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Tested-by: Nick Desaulniers Tested-by: Sedat Dilek Reviewed-by: Kees Cook Reviewed-by: Ard Biesheuvel Reviewed-by: Fangrui Song Link: https://lore.kernel.org/r/20200731230820.1742553-6-keescook@chromium.org --- arch/x86/boot/compressed/head_32.S | 64 +++++++----------- arch/x86/boot/compressed/head_64.S | 104 ++++++++++++++++++----------- 2 files changed, 90 insertions(+), 78 deletions(-) diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index 39f0bb43218f..8c1a4f5610f5 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -33,26 +33,10 @@ #include /* - * The 32-bit x86 assembler in binutils 2.26 will generate R_386_GOT32X - * relocation to get the symbol address in PIC. When the compressed x86 - * kernel isn't built as PIC, the linker optimizes R_386_GOT32X - * relocations to their fixed symbol addresses. However, when the - * compressed x86 kernel is loaded at a different address, it leads - * to the following load failure: - * - * Failed to allocate space for phdrs - * - * during the decompression stage. - * - * If the compressed x86 kernel is relocatable at run-time, it should be - * compiled with -fPIE, instead of -fPIC, if possible and should be built as - * Position Independent Executable (PIE) so that linker won't optimize - * R_386_GOT32X relocation to its fixed symbol address. Older - * linkers generate R_386_32 relocations against locally defined symbols, - * _bss, _ebss and _end, in PIE. It isn't wrong, just less optimal than - * R_386_RELATIVE. But the x86 kernel fails to properly handle R_386_32 - * relocations when relocating the kernel. To generate R_386_RELATIVE - * relocations, we mark _bss, _ebss and _end as hidden: + * These symbols needed to be marked as .hidden to prevent the BFD linker from + * generating R_386_32 (rather than R_386_RELATIVE) relocations for them when + * the 32-bit compressed kernel is linked as PIE. This is no longer necessary, + * but it doesn't hurt to keep them .hidden. */ .hidden _bss .hidden _ebss @@ -74,10 +58,10 @@ SYM_FUNC_START(startup_32) leal (BP_scratch+4)(%esi), %esp call 1f 1: popl %edx - subl $1b, %edx + addl $_GLOBAL_OFFSET_TABLE_+(.-1b), %edx /* Load new GDT */ - leal gdt(%edx), %eax + leal gdt@GOTOFF(%edx), %eax movl %eax, 2(%eax) lgdt (%eax) @@ -90,14 +74,16 @@ SYM_FUNC_START(startup_32) movl %eax, %ss /* - * %edx contains the address we are loaded at by the boot loader and %ebx - * contains the address where we should move the kernel image temporarily - * for safe in-place decompression. %ebp contains the address that the kernel - * will be decompressed to. + * %edx contains the address we are loaded at by the boot loader (plus the + * offset to the GOT). The below code calculates %ebx to be the address where + * we should move the kernel image temporarily for safe in-place decompression + * (again, plus the offset to the GOT). + * + * %ebp is calculated to be the address that the kernel will be decompressed to. */ #ifdef CONFIG_RELOCATABLE - movl %edx, %ebx + leal startup_32@GOTOFF(%edx), %ebx #ifdef CONFIG_EFI_STUB /* @@ -108,7 +94,7 @@ SYM_FUNC_START(startup_32) * image_offset = startup_32 - image_base * Otherwise image_offset will be zero and has no effect on the calculations. */ - subl image_offset(%edx), %ebx + subl image_offset@GOTOFF(%edx), %ebx #endif movl BP_kernel_alignment(%esi), %eax @@ -125,10 +111,10 @@ SYM_FUNC_START(startup_32) movl %ebx, %ebp // Save the output address for later /* Target address to relocate to for decompression */ addl BP_init_size(%esi), %ebx - subl $_end, %ebx + subl $_end@GOTOFF, %ebx /* Set up the stack */ - leal boot_stack_end(%ebx), %esp + leal boot_stack_end@GOTOFF(%ebx), %esp /* Zero EFLAGS */ pushl $0 @@ -139,8 +125,8 @@ SYM_FUNC_START(startup_32) * where decompression in place becomes safe. */ pushl %esi - leal (_bss-4)(%edx), %esi - leal (_bss-4)(%ebx), %edi + leal (_bss@GOTOFF-4)(%edx), %esi + leal (_bss@GOTOFF-4)(%ebx), %edi movl $(_bss - startup_32), %ecx shrl $2, %ecx std @@ -153,14 +139,14 @@ SYM_FUNC_START(startup_32) * during extract_kernel below. To avoid any issues, repoint the GDTR * to the new copy of the GDT. */ - leal gdt(%ebx), %eax + leal gdt@GOTOFF(%ebx), %eax movl %eax, 2(%eax) lgdt (%eax) /* * Jump to the relocated address. */ - leal .Lrelocated(%ebx), %eax + leal .Lrelocated@GOTOFF(%ebx), %eax jmp *%eax SYM_FUNC_END(startup_32) @@ -170,7 +156,7 @@ SYM_FUNC_START_ALIAS(efi_stub_entry) add $0x4, %esp movl 8(%esp), %esi /* save boot_params pointer */ call efi_main - leal startup_32(%eax), %eax + /* efi_main returns the possibly relocated address of startup_32 */ jmp *%eax SYM_FUNC_END(efi32_stub_entry) SYM_FUNC_END_ALIAS(efi_stub_entry) @@ -183,8 +169,8 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated) * Clear BSS (stack is currently empty) */ xorl %eax, %eax - leal _bss(%ebx), %edi - leal _ebss(%ebx), %ecx + leal _bss@GOTOFF(%ebx), %edi + leal _ebss@GOTOFF(%ebx), %ecx subl %edi, %ecx shrl $2, %ecx rep stosl @@ -198,9 +184,9 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated) pushl %ebp /* output address */ pushl $z_input_len /* input_len */ - leal input_data(%ebx), %eax + leal input_data@GOTOFF(%ebx), %eax pushl %eax /* input_data */ - leal boot_heap(%ebx), %eax + leal boot_heap@GOTOFF(%ebx), %eax pushl %eax /* heap area */ pushl %esi /* real mode pointer */ call extract_kernel /* returns kernel location in %eax */ diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index bf1ab30acc5b..11429092c224 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -43,6 +43,32 @@ .hidden _end __HEAD + +/* + * This macro gives the relative virtual address of X, i.e. the offset of X + * from startup_32. This is the same as the link-time virtual address of X, + * since startup_32 is at 0, but defining it this way tells the + * assembler/linker that we do not want the actual run-time address of X. This + * prevents the linker from trying to create unwanted run-time relocation + * entries for the reference when the compressed kernel is linked as PIE. + * + * A reference X(%reg) will result in the link-time VA of X being stored with + * the instruction, and a run-time R_X86_64_RELATIVE relocation entry that + * adds the 64-bit base address where the kernel is loaded. + * + * Replacing it with (X-startup_32)(%reg) results in the offset being stored, + * and no run-time relocation. + * + * The macro should be used as a displacement with a base register containing + * the run-time address of startup_32 [i.e. rva(X)(%reg)], or as an immediate + * [$ rva(X)]. + * + * This macro can only be used from within the .head.text section, since the + * expression requires startup_32 to be in the same section as the code being + * assembled. + */ +#define rva(X) ((X) - startup_32) + .code32 SYM_FUNC_START(startup_32) /* @@ -65,10 +91,10 @@ SYM_FUNC_START(startup_32) leal (BP_scratch+4)(%esi), %esp call 1f 1: popl %ebp - subl $1b, %ebp + subl $ rva(1b), %ebp /* Load new GDT with the 64bit segments using 32bit descriptor */ - leal gdt(%ebp), %eax + leal rva(gdt)(%ebp), %eax movl %eax, 2(%eax) lgdt (%eax) @@ -81,7 +107,7 @@ SYM_FUNC_START(startup_32) movl %eax, %ss /* setup a stack and make sure cpu supports long mode. */ - leal boot_stack_end(%ebp), %esp + leal rva(boot_stack_end)(%ebp), %esp call verify_cpu testl %eax, %eax @@ -108,7 +134,7 @@ SYM_FUNC_START(startup_32) * image_offset = startup_32 - image_base * Otherwise image_offset will be zero and has no effect on the calculations. */ - subl image_offset(%ebp), %ebx + subl rva(image_offset)(%ebp), %ebx #endif movl BP_kernel_alignment(%esi), %eax @@ -124,7 +150,7 @@ SYM_FUNC_START(startup_32) /* Target address to relocate to for decompression */ addl BP_init_size(%esi), %ebx - subl $_end, %ebx + subl $ rva(_end), %ebx /* * Prepare for entering 64 bit mode @@ -152,19 +178,19 @@ SYM_FUNC_START(startup_32) 1: /* Initialize Page tables to 0 */ - leal pgtable(%ebx), %edi + leal rva(pgtable)(%ebx), %edi xorl %eax, %eax movl $(BOOT_INIT_PGT_SIZE/4), %ecx rep stosl /* Build Level 4 */ - leal pgtable + 0(%ebx), %edi + leal rva(pgtable + 0)(%ebx), %edi leal 0x1007 (%edi), %eax movl %eax, 0(%edi) addl %edx, 4(%edi) /* Build Level 3 */ - leal pgtable + 0x1000(%ebx), %edi + leal rva(pgtable + 0x1000)(%ebx), %edi leal 0x1007(%edi), %eax movl $4, %ecx 1: movl %eax, 0x00(%edi) @@ -175,7 +201,7 @@ SYM_FUNC_START(startup_32) jnz 1b /* Build Level 2 */ - leal pgtable + 0x2000(%ebx), %edi + leal rva(pgtable + 0x2000)(%ebx), %edi movl $0x00000183, %eax movl $2048, %ecx 1: movl %eax, 0(%edi) @@ -186,7 +212,7 @@ SYM_FUNC_START(startup_32) jnz 1b /* Enable the boot page tables */ - leal pgtable(%ebx), %eax + leal rva(pgtable)(%ebx), %eax movl %eax, %cr3 /* Enable Long mode in EFER (Extended Feature Enable Register) */ @@ -211,14 +237,14 @@ SYM_FUNC_START(startup_32) * We place all of the values on our mini stack so lret can * used to perform that far jump. */ - leal startup_64(%ebp), %eax + leal rva(startup_64)(%ebp), %eax #ifdef CONFIG_EFI_MIXED - movl efi32_boot_args(%ebp), %edi + movl rva(efi32_boot_args)(%ebp), %edi cmp $0, %edi jz 1f - leal efi64_stub_entry(%ebp), %eax - movl efi32_boot_args+4(%ebp), %esi - movl efi32_boot_args+8(%ebp), %edx // saved bootparams pointer + leal rva(efi64_stub_entry)(%ebp), %eax + movl rva(efi32_boot_args+4)(%ebp), %esi + movl rva(efi32_boot_args+8)(%ebp), %edx // saved bootparams pointer cmpl $0, %edx jnz 1f /* @@ -229,7 +255,7 @@ SYM_FUNC_START(startup_32) * the correct stack alignment for entry. */ subl $40, %esp - leal efi_pe_entry(%ebp), %eax + leal rva(efi_pe_entry)(%ebp), %eax movl %edi, %ecx // MS calling convention movl %esi, %edx 1: @@ -255,18 +281,18 @@ SYM_FUNC_START(efi32_stub_entry) call 1f 1: pop %ebp - subl $1b, %ebp + subl $ rva(1b), %ebp - movl %esi, efi32_boot_args+8(%ebp) + movl %esi, rva(efi32_boot_args+8)(%ebp) SYM_INNER_LABEL(efi32_pe_stub_entry, SYM_L_LOCAL) - movl %ecx, efi32_boot_args(%ebp) - movl %edx, efi32_boot_args+4(%ebp) - movb $0, efi_is64(%ebp) + movl %ecx, rva(efi32_boot_args)(%ebp) + movl %edx, rva(efi32_boot_args+4)(%ebp) + movb $0, rva(efi_is64)(%ebp) /* Save firmware GDTR and code/data selectors */ - sgdtl efi32_boot_gdt(%ebp) - movw %cs, efi32_boot_cs(%ebp) - movw %ds, efi32_boot_ds(%ebp) + sgdtl rva(efi32_boot_gdt)(%ebp) + movw %cs, rva(efi32_boot_cs)(%ebp) + movw %ds, rva(efi32_boot_ds)(%ebp) /* Disable paging */ movl %cr0, %eax @@ -345,11 +371,11 @@ SYM_CODE_START(startup_64) /* Target address to relocate to for decompression */ movl BP_init_size(%rsi), %ebx - subl $_end, %ebx + subl $ rva(_end), %ebx addq %rbp, %rbx /* Set up the stack */ - leaq boot_stack_end(%rbx), %rsp + leaq rva(boot_stack_end)(%rbx), %rsp /* * At this point we are in long mode with 4-level paging enabled, @@ -423,7 +449,7 @@ SYM_CODE_START(startup_64) lretq trampoline_return: /* Restore the stack, the 32-bit trampoline uses its own stack */ - leaq boot_stack_end(%rbx), %rsp + leaq rva(boot_stack_end)(%rbx), %rsp /* * cleanup_trampoline() would restore trampoline memory. @@ -435,7 +461,7 @@ trampoline_return: * this function call. */ pushq %rsi - leaq top_pgtable(%rbx), %rdi + leaq rva(top_pgtable)(%rbx), %rdi call cleanup_trampoline popq %rsi @@ -449,9 +475,9 @@ trampoline_return: */ pushq %rsi leaq (_bss-8)(%rip), %rsi - leaq (_bss-8)(%rbx), %rdi - movq $_bss /* - $startup_32 */, %rcx - shrq $3, %rcx + leaq rva(_bss-8)(%rbx), %rdi + movl $(_bss - startup_32), %ecx + shrl $3, %ecx std rep movsq cld @@ -462,15 +488,15 @@ trampoline_return: * during extract_kernel below. To avoid any issues, repoint the GDTR * to the new copy of the GDT. */ - leaq gdt64(%rbx), %rax - leaq gdt(%rbx), %rdx + leaq rva(gdt64)(%rbx), %rax + leaq rva(gdt)(%rbx), %rdx movq %rdx, 2(%rax) lgdt (%rax) /* * Jump to the relocated address. */ - leaq .Lrelocated(%rbx), %rax + leaq rva(.Lrelocated)(%rbx), %rax jmp *%rax SYM_CODE_END(startup_64) @@ -482,7 +508,7 @@ SYM_FUNC_START_ALIAS(efi_stub_entry) movq %rdx, %rbx /* save boot_params pointer */ call efi_main movq %rbx,%rsi - leaq startup_64(%rax), %rax + leaq rva(startup_64)(%rax), %rax jmp *%rax SYM_FUNC_END(efi64_stub_entry) SYM_FUNC_END_ALIAS(efi_stub_entry) @@ -645,7 +671,7 @@ SYM_DATA(efi_is64, .byte 1) #define BS32_handle_protocol 88 // offsetof(efi_boot_services_32_t, handle_protocol) #define LI32_image_base 32 // offsetof(efi_loaded_image_32_t, image_base) - .text + __HEAD .code32 SYM_FUNC_START(efi32_pe_entry) /* @@ -667,12 +693,12 @@ SYM_FUNC_START(efi32_pe_entry) call 1f 1: pop %ebx - subl $1b, %ebx + subl $ rva(1b), %ebx /* Get the loaded image protocol pointer from the image handle */ leal -4(%ebp), %eax pushl %eax // &loaded_image - leal loaded_image_proto(%ebx), %eax + leal rva(loaded_image_proto)(%ebx), %eax pushl %eax // pass the GUID address pushl 8(%ebp) // pass the image handle @@ -707,7 +733,7 @@ SYM_FUNC_START(efi32_pe_entry) * use it before we get to the 64-bit efi_pe_entry() in C code. */ subl %esi, %ebx - movl %ebx, image_offset(%ebp) // save image_offset + movl %ebx, rva(image_offset)(%ebp) // save image_offset jmp efi32_pe_stub_entry 2: popl %edi // restore callee-save registers From 3f086189cd3641d212949ff044d8e4486c93d55e Mon Sep 17 00:00:00 2001 From: Arvind Sankar Date: Fri, 31 Jul 2020 16:07:50 -0700 Subject: [PATCH 06/36] x86/boot: Remove run-time relocations from head_{32,64}.S 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 Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Tested-by: Nick Desaulniers Tested-by: Sedat Dilek Reviewed-by: Kees Cook Reviewed-by: Ard Biesheuvel Reviewed-by: Fangrui Song Link: https://lore.kernel.org/r/20200731230820.1742553-7-keescook@chromium.org --- arch/x86/boot/compressed/Makefile | 12 ++---------- arch/x86/boot/compressed/head_32.S | 17 ++++++++--------- arch/x86/boot/compressed/head_64.S | 4 ++-- arch/x86/boot/compressed/mkpiggy.c | 6 ++++++ 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 7c687a770537..7d25089c5a7b 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -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 diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index 8c1a4f5610f5..659fad53ca82 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -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 /* diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index 11429092c224..9e46729cf162 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -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 diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c index 7e01248765b2..52aa56cdbacc 100644 --- a/arch/x86/boot/compressed/mkpiggy.c +++ b/arch/x86/boot/compressed/mkpiggy.c @@ -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) From 527afc212231ea9d585b7709c0ab73263ecf0c85 Mon Sep 17 00:00:00 2001 From: Arvind Sankar Date: Fri, 31 Jul 2020 16:07:51 -0700 Subject: [PATCH 07/36] x86/boot: Check that there are no run-time relocations Add a linker script check that there are no run-time relocations, and remove the old one that tries to check via looking for specially-named sections in the object files. Drop the tests for -fPIE compiler option and -pie linker option, as they are available in all supported gcc and binutils versions (as well as clang and lld). Signed-off-by: Arvind Sankar Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Tested-by: Nick Desaulniers Tested-by: Sedat Dilek Reviewed-by: Kees Cook Reviewed-by: Ard Biesheuvel Reviewed-by: Fangrui Song Reviewed-by: Sedat Dilek Link: https://lore.kernel.org/r/20200731230820.1742553-8-keescook@chromium.org --- arch/x86/boot/compressed/Makefile | 28 +++----------------------- arch/x86/boot/compressed/vmlinux.lds.S | 8 ++++++++ 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 7d25089c5a7b..753d57266757 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -29,7 +29,7 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \ vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4 vmlinux.bin.zst KBUILD_CFLAGS := -m$(BITS) -O2 -KBUILD_CFLAGS += -fno-strict-aliasing $(call cc-option, -fPIE, -fPIC) +KBUILD_CFLAGS += -fno-strict-aliasing -fPIE KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING cflags-$(CONFIG_X86_32) := -march=i386 cflags-$(CONFIG_X86_64) := -mcmodel=small @@ -52,7 +52,7 @@ 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. -LDFLAGS_vmlinux := $(call ld-option, -pie) $(call ld-option, --no-dynamic-linker) +LDFLAGS_vmlinux := -pie $(call ld-option, --no-dynamic-linker) LDFLAGS_vmlinux += -T hostprogs := mkpiggy @@ -87,30 +87,8 @@ vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o efi-obj-$(CONFIG_EFI_STUB) = $(objtree)/drivers/firmware/efi/libstub/lib.a -# The compressed kernel is built with -fPIC/-fPIE so that a boot loader -# can place it anywhere in memory and it will still run. However, since -# it is executed as-is without any ELF relocation processing performed -# (and has already had all relocation sections stripped from the binary), -# none of the code can use data relocations (e.g. static assignments of -# pointer values), since they will be meaningless at runtime. This check -# will refuse to link the vmlinux if any of these relocations are found. -quiet_cmd_check_data_rel = DATAREL $@ -define cmd_check_data_rel - for obj in $(filter %.o,$^); do \ - $(READELF) -S $$obj | grep -qF .rel.local && { \ - echo "error: $$obj has data relocations!" >&2; \ - exit 1; \ - } || true; \ - done -endef - -# We need to run two commands under "if_changed", so merge them into a -# single invocation. -quiet_cmd_check-and-link-vmlinux = LD $@ - cmd_check-and-link-vmlinux = $(cmd_check_data_rel); $(cmd_ld) - $(obj)/vmlinux: $(vmlinux-objs-y) $(efi-obj-y) FORCE - $(call if_changed,check-and-link-vmlinux) + $(call if_changed,ld) OBJCOPYFLAGS_vmlinux.bin := -R .comment -S $(obj)/vmlinux.bin: vmlinux FORCE diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S index a4a4a59a2628..29df99b6cc64 100644 --- a/arch/x86/boot/compressed/vmlinux.lds.S +++ b/arch/x86/boot/compressed/vmlinux.lds.S @@ -42,6 +42,12 @@ SECTIONS *(.rodata.*) _erodata = . ; } + .rel.dyn : { + *(.rel.*) + } + .rela.dyn : { + *(.rela.*) + } .got : { *(.got) } @@ -85,3 +91,5 @@ ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18, "Unexpected GOT/PLT en #else ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0xc, "Unexpected GOT/PLT entries detected!") #endif + +ASSERT(SIZEOF(.rel.dyn) == 0 && SIZEOF(.rela.dyn) == 0, "Unexpected run-time relocations detected!") From 03c2b85cb7f13e9bd82cbe4201ede52177d433f5 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:42 -0700 Subject: [PATCH 08/36] vmlinux.lds.h: Create COMMON_DISCARDS Collect the common DISCARD sections for architectures that need more specialized discard control than what the standard DISCARDS section provides. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Cc: linux-arch@vger.kernel.org Link: https://lore.kernel.org/r/20200821194310.3089815-2-keescook@chromium.org --- include/asm-generic/vmlinux.lds.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 7616ff0b96ec..184b23d62784 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -954,13 +954,16 @@ EXIT_DATA #endif +#define COMMON_DISCARDS \ + *(.discard) \ + *(.discard.*) \ + *(.modinfo) + #define DISCARDS \ /DISCARD/ : { \ EXIT_DISCARDS \ EXIT_CALL \ - *(.discard) \ - *(.discard.*) \ - *(.modinfo) \ + COMMON_DISCARDS \ } /** From dfbe69689b4dee19021d8c315a5137b4790b5634 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:43 -0700 Subject: [PATCH 09/36] vmlinux.lds.h: Add .gnu.version* to COMMON_DISCARDS For vmlinux linking, no architecture uses the .gnu.version* sections, so remove it via the COMMON_DISCARDS macro in preparation for adding --orphan-handling=warn more widely. This is a work-around for what appears to be a bug[1] in ld.bfd which warns for this synthetic section even when none is found in input objects, and even when no section is emitted for an output object[2]. [1] https://sourceware.org/bugzilla/show_bug.cgi?id=26153 [2] https://lore.kernel.org/lkml/202006221524.CEB86E036B@keescook/ Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Reviewed-by: Fangrui Song Cc: linux-arch@vger.kernel.org Link: https://lore.kernel.org/r/20200821194310.3089815-3-keescook@chromium.org --- include/asm-generic/vmlinux.lds.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 184b23d62784..f1f02a2f71b7 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -957,7 +957,9 @@ #define COMMON_DISCARDS \ *(.discard) \ *(.discard.*) \ - *(.modinfo) + *(.modinfo) \ + /* ld.bfd warns about .gnu.version* even when not emitted */ \ + *(.gnu.version*) \ #define DISCARDS \ /DISCARD/ : { \ From d812db78288d76d1e8c6df3a840c41a8875f6468 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:44 -0700 Subject: [PATCH 10/36] vmlinux.lds.h: Avoid KASAN and KCSAN's unwanted sections KASAN (-fsanitize=kernel-address) and KCSAN (-fsanitize=thread) produce unwanted[1] .eh_frame and .init_array.* sections. Add them to COMMON_DISCARDS, except with CONFIG_CONSTRUCTORS, which wants to keep .init_array.* sections. [1] https://bugs.llvm.org/show_bug.cgi?id=46478 Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Tested-by: Marco Elver Cc: linux-arch@vger.kernel.org Link: https://lore.kernel.org/r/20200821194310.3089815-4-keescook@chromium.org --- include/asm-generic/vmlinux.lds.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index f1f02a2f71b7..6b89a03e636e 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -954,7 +954,27 @@ EXIT_DATA #endif +/* + * Clang's -fsanitize=kernel-address and -fsanitize=thread produce + * unwanted sections (.eh_frame and .init_array.*), but + * CONFIG_CONSTRUCTORS wants to keep any .init_array.* sections. + * https://bugs.llvm.org/show_bug.cgi?id=46478 + */ +#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KCSAN) +# ifdef CONFIG_CONSTRUCTORS +# define SANITIZER_DISCARDS \ + *(.eh_frame) +# else +# define SANITIZER_DISCARDS \ + *(.init_array) *(.init_array.*) \ + *(.eh_frame) +# endif +#else +# define SANITIZER_DISCARDS +#endif + #define COMMON_DISCARDS \ + SANITIZER_DISCARDS \ *(.discard) \ *(.discard.*) \ *(.modinfo) \ From c604abc3f6e3030f3a3022b184ed7d3780c34d30 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:45 -0700 Subject: [PATCH 11/36] vmlinux.lds.h: Split ELF_DETAILS from STABS_DEBUG The .comment section doesn't belong in STABS_DEBUG. Split it out into a new macro named ELF_DETAILS. This will gain other non-debug sections that need to be accounted for when linking with --orphan-handling=warn. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Cc: linux-arch@vger.kernel.org Link: https://lore.kernel.org/r/20200821194310.3089815-5-keescook@chromium.org --- arch/alpha/kernel/vmlinux.lds.S | 1 + arch/arc/kernel/vmlinux.lds.S | 1 + arch/arm/kernel/vmlinux-xip.lds.S | 1 + arch/arm/kernel/vmlinux.lds.S | 1 + arch/arm64/kernel/vmlinux.lds.S | 1 + arch/csky/kernel/vmlinux.lds.S | 1 + arch/hexagon/kernel/vmlinux.lds.S | 1 + arch/ia64/kernel/vmlinux.lds.S | 1 + arch/mips/kernel/vmlinux.lds.S | 1 + arch/nds32/kernel/vmlinux.lds.S | 1 + arch/nios2/kernel/vmlinux.lds.S | 1 + arch/openrisc/kernel/vmlinux.lds.S | 1 + arch/parisc/boot/compressed/vmlinux.lds.S | 1 + arch/parisc/kernel/vmlinux.lds.S | 1 + arch/powerpc/kernel/vmlinux.lds.S | 2 +- arch/riscv/kernel/vmlinux.lds.S | 1 + arch/s390/kernel/vmlinux.lds.S | 1 + arch/sh/kernel/vmlinux.lds.S | 1 + arch/sparc/kernel/vmlinux.lds.S | 1 + arch/um/kernel/dyn.lds.S | 2 +- arch/um/kernel/uml.lds.S | 2 +- arch/x86/boot/compressed/vmlinux.lds.S | 2 ++ arch/x86/kernel/vmlinux.lds.S | 1 + include/asm-generic/vmlinux.lds.h | 8 ++++++-- 24 files changed, 30 insertions(+), 5 deletions(-) diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S index bc6f727278fd..5b78d640725d 100644 --- a/arch/alpha/kernel/vmlinux.lds.S +++ b/arch/alpha/kernel/vmlinux.lds.S @@ -72,6 +72,7 @@ SECTIONS STABS_DEBUG DWARF_DEBUG + ELF_DETAILS DISCARDS } diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S index 54139a6f469b..33ce59d91461 100644 --- a/arch/arc/kernel/vmlinux.lds.S +++ b/arch/arc/kernel/vmlinux.lds.S @@ -122,6 +122,7 @@ SECTIONS _end = . ; STABS_DEBUG + ELF_DETAILS DISCARDS .arcextmap 0 : { diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S index 6d2be994ae58..3d4e88f08196 100644 --- a/arch/arm/kernel/vmlinux-xip.lds.S +++ b/arch/arm/kernel/vmlinux-xip.lds.S @@ -152,6 +152,7 @@ SECTIONS _end = .; STABS_DEBUG + ELF_DETAILS } /* diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 7f24bc08403e..5592f14b7e35 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -151,6 +151,7 @@ SECTIONS _end = .; STABS_DEBUG + ELF_DETAILS } #ifdef CONFIG_STRICT_KERNEL_RWX diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index ec8e894684a7..13fc2ec46aae 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -241,6 +241,7 @@ SECTIONS _end = .; STABS_DEBUG + ELF_DETAILS HEAD_SYMBOLS } diff --git a/arch/csky/kernel/vmlinux.lds.S b/arch/csky/kernel/vmlinux.lds.S index f05b413df328..f03033e17c29 100644 --- a/arch/csky/kernel/vmlinux.lds.S +++ b/arch/csky/kernel/vmlinux.lds.S @@ -109,6 +109,7 @@ SECTIONS STABS_DEBUG DWARF_DEBUG + ELF_DETAILS DISCARDS } diff --git a/arch/hexagon/kernel/vmlinux.lds.S b/arch/hexagon/kernel/vmlinux.lds.S index 0ca2471ddb9f..35b18e55eae8 100644 --- a/arch/hexagon/kernel/vmlinux.lds.S +++ b/arch/hexagon/kernel/vmlinux.lds.S @@ -67,5 +67,6 @@ SECTIONS STABS_DEBUG DWARF_DEBUG + ELF_DETAILS } diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index d259690eb91a..9b265783be6a 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -218,6 +218,7 @@ SECTIONS { STABS_DEBUG DWARF_DEBUG + ELF_DETAILS /* Default discards */ DISCARDS diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index f185a85a27c1..5e97e9d02f98 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -202,6 +202,7 @@ SECTIONS STABS_DEBUG DWARF_DEBUG + ELF_DETAILS /* These must appear regardless of . */ .gptab.sdata : { diff --git a/arch/nds32/kernel/vmlinux.lds.S b/arch/nds32/kernel/vmlinux.lds.S index 7a6c1cefe3fe..6a91b965fb1e 100644 --- a/arch/nds32/kernel/vmlinux.lds.S +++ b/arch/nds32/kernel/vmlinux.lds.S @@ -64,6 +64,7 @@ SECTIONS STABS_DEBUG DWARF_DEBUG + ELF_DETAILS DISCARDS } diff --git a/arch/nios2/kernel/vmlinux.lds.S b/arch/nios2/kernel/vmlinux.lds.S index c55a7cfa1075..126e114744cb 100644 --- a/arch/nios2/kernel/vmlinux.lds.S +++ b/arch/nios2/kernel/vmlinux.lds.S @@ -58,6 +58,7 @@ SECTIONS STABS_DEBUG DWARF_DEBUG + ELF_DETAILS DISCARDS } diff --git a/arch/openrisc/kernel/vmlinux.lds.S b/arch/openrisc/kernel/vmlinux.lds.S index 60449fd7f16f..d287dbb84d0f 100644 --- a/arch/openrisc/kernel/vmlinux.lds.S +++ b/arch/openrisc/kernel/vmlinux.lds.S @@ -115,6 +115,7 @@ SECTIONS /* Throw in the debugging sections */ STABS_DEBUG DWARF_DEBUG + ELF_DETAILS /* Sections to be discarded -- must be last */ DISCARDS diff --git a/arch/parisc/boot/compressed/vmlinux.lds.S b/arch/parisc/boot/compressed/vmlinux.lds.S index 2ac3a643f2eb..ab7b43990857 100644 --- a/arch/parisc/boot/compressed/vmlinux.lds.S +++ b/arch/parisc/boot/compressed/vmlinux.lds.S @@ -84,6 +84,7 @@ SECTIONS } STABS_DEBUG + ELF_DETAILS .note 0 : { *(.note) } /* Sections to be discarded */ diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 53e29d88f99c..2769eb991f58 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -164,6 +164,7 @@ SECTIONS _end = . ; STABS_DEBUG + ELF_DETAILS .note 0 : { *(.note) } /* Sections to be discarded */ diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 326e113d2e45..e0548b4950de 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -360,8 +360,8 @@ SECTIONS PROVIDE32 (end = .); STABS_DEBUG - DWARF_DEBUG + ELF_DETAILS DISCARDS /DISCARD/ : { diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S index f3586e31ed1e..6f3af7bbc49d 100644 --- a/arch/riscv/kernel/vmlinux.lds.S +++ b/arch/riscv/kernel/vmlinux.lds.S @@ -97,6 +97,7 @@ SECTIONS STABS_DEBUG DWARF_DEBUG + ELF_DETAILS DISCARDS } diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 37695499717d..177ccfbda40a 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -181,6 +181,7 @@ SECTIONS /* Debugging sections. */ STABS_DEBUG DWARF_DEBUG + ELF_DETAILS /* Sections to be discarded */ DISCARDS diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index bde7a6c01aaf..3161b9ccd2a5 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S @@ -76,6 +76,7 @@ SECTIONS STABS_DEBUG DWARF_DEBUG + ELF_DETAILS DISCARDS } diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S index f99e99e58075..d55ae65a07ad 100644 --- a/arch/sparc/kernel/vmlinux.lds.S +++ b/arch/sparc/kernel/vmlinux.lds.S @@ -187,6 +187,7 @@ SECTIONS STABS_DEBUG DWARF_DEBUG + ELF_DETAILS DISCARDS } diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index f5001481010c..dacbfabf66d8 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -164,8 +164,8 @@ SECTIONS PROVIDE (end = .); STABS_DEBUG - DWARF_DEBUG + ELF_DETAILS DISCARDS } diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index 3b6dab3d4501..45d957d7004c 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -108,8 +108,8 @@ SECTIONS PROVIDE (end = .); STABS_DEBUG - DWARF_DEBUG + ELF_DETAILS DISCARDS } diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S index 29df99b6cc64..3c2ee9a5bf43 100644 --- a/arch/x86/boot/compressed/vmlinux.lds.S +++ b/arch/x86/boot/compressed/vmlinux.lds.S @@ -82,6 +82,8 @@ SECTIONS . = ALIGN(PAGE_SIZE); /* keep ZO size page aligned */ _end = .; + ELF_DETAILS + DISCARDS } diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 9a03e5b23135..0cc035cb15f1 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -411,6 +411,7 @@ SECTIONS STABS_DEBUG DWARF_DEBUG + ELF_DETAILS DISCARDS } diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 6b89a03e636e..cadcbc3cdabd 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -34,6 +34,7 @@ * * STABS_DEBUG * DWARF_DEBUG + * ELF_DETAILS * * DISCARDS // must be the last * } @@ -811,14 +812,17 @@ .debug_macro 0 : { *(.debug_macro) } \ .debug_addr 0 : { *(.debug_addr) } - /* Stabs debugging sections. */ +/* Stabs debugging sections. */ #define STABS_DEBUG \ .stab 0 : { *(.stab) } \ .stabstr 0 : { *(.stabstr) } \ .stab.excl 0 : { *(.stab.excl) } \ .stab.exclstr 0 : { *(.stab.exclstr) } \ .stab.index 0 : { *(.stab.index) } \ - .stab.indexstr 0 : { *(.stab.indexstr) } \ + .stab.indexstr 0 : { *(.stab.indexstr) } + +/* Required sections not related to debugging. */ +#define ELF_DETAILS \ .comment 0 : { *(.comment) } #ifdef CONFIG_GENERIC_BUG From a840c4de569f610bc5ee043b613c35b779d23186 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:46 -0700 Subject: [PATCH 12/36] vmlinux.lds.h: Add .symtab, .strtab, and .shstrtab to ELF_DETAILS When linking vmlinux with LLD, the synthetic sections .symtab, .strtab, and .shstrtab are listed as orphaned. Add them to the ELF_DETAILS section so there will be no warnings when --orphan-handling=warn is used more widely. (They are added above comment as it is the more common order[1].) ld.lld: warning: :(.symtab) is being placed in '.symtab' ld.lld: warning: :(.shstrtab) is being placed in '.shstrtab' ld.lld: warning: :(.strtab) is being placed in '.strtab' [1] https://lore.kernel.org/lkml/20200622224928.o2a7jkq33guxfci4@google.com/ Reported-by: Fangrui Song Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Cc: linux-arch@vger.kernel.org Link: https://lore.kernel.org/r/20200821194310.3089815-6-keescook@chromium.org --- include/asm-generic/vmlinux.lds.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index cadcbc3cdabd..98d013dcc11a 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -823,7 +823,10 @@ /* Required sections not related to debugging. */ #define ELF_DETAILS \ - .comment 0 : { *(.comment) } + .comment 0 : { *(.comment) } \ + .symtab 0 : { *(.symtab) } \ + .strtab 0 : { *(.strtab) } \ + .shstrtab 0 : { *(.shstrtab) } #ifdef CONFIG_GENERIC_BUG #define BUG_TABLE \ From eff8728fe69880d3f7983bec3fb6cea4c306261f Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Fri, 21 Aug 2020 12:42:47 -0700 Subject: [PATCH 13/36] vmlinux.lds.h: Add PGO and AutoFDO input sections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Basically, consider .text.{hot|unlikely|unknown}.* part of .text, too. When compiling with profiling information (collected via PGO instrumentations or AutoFDO sampling), Clang will separate code into .text.hot, .text.unlikely, or .text.unknown sections based on profiling information. After D79600 (clang-11), these sections will have a trailing `.` suffix, ie. .text.hot., .text.unlikely., .text.unknown.. When using -ffunction-sections together with profiling infomation, either explicitly (FGKASLR) or implicitly (LTO), code may be placed in sections following the convention: .text.hot., .text.unlikely., .text.unknown. where , , and are functions. (This produces one section per function; we generally try to merge these all back via linker script so that we don't have 50k sections). For the above cases, we need to teach our linker scripts that such sections might exist and that we'd explicitly like them grouped together, otherwise we can wind up with code outside of the _stext/_etext boundaries that might not be mapped properly for some architectures, resulting in boot failures. If the linker script is not told about possible input sections, then where the section is placed as output is a heuristic-laiden mess that's non-portable between linkers (ie. BFD and LLD), and has resulted in many hard to debug bugs. Kees Cook is working on cleaning this up by adding --orphan-handling=warn linker flag used in ARCH=powerpc to additional architectures. In the case of linker scripts, borrowing from the Zen of Python: explicit is better than implicit. Also, ld.bfd's internal linker script considers .text.hot AND .text.hot.* to be part of .text, as well as .text.unlikely and .text.unlikely.*. I didn't see support for .text.unknown.*, and didn't see Clang producing such code in our kernel builds, but I see code in LLVM that can produce such section names if profiling information is missing. That may point to a larger issue with generating or collecting profiles, but I would much rather be safe and explicit than have to debug yet another issue related to orphan section placement. Reported-by: Jian Cai Suggested-by: Fāng-ruì Sòng Signed-off-by: Nick Desaulniers Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Tested-by: Luis Lozano Tested-by: Manoj Gupta Acked-by: Kees Cook Cc: linux-arch@vger.kernel.org Cc: stable@vger.kernel.org Link: https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=add44f8d5c5c05e08b11e033127a744d61c26aee Link: https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=1de778ed23ce7492c523d5850c6c6dbb34152655 Link: https://reviews.llvm.org/D79600 Link: https://bugs.chromium.org/p/chromium/issues/detail?id=1084760 Link: https://lore.kernel.org/r/20200821194310.3089815-7-keescook@chromium.org Debugged-by: Luis Lozano --- include/asm-generic/vmlinux.lds.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 98d013dcc11a..91dcfb91ac45 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -581,7 +581,10 @@ */ #define TEXT_TEXT \ ALIGN_FUNCTION(); \ - *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \ + *(.text.hot .text.hot.*) \ + *(TEXT_MAIN .text.fixup) \ + *(.text.unlikely .text.unlikely.*) \ + *(.text.unknown .text.unknown.*) \ NOINSTR_TEXT \ *(.text..refcount) \ *(.ref.text) \ From e2179a09ab089d3423751bd2b0c884ddb3eabe84 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:48 -0700 Subject: [PATCH 14/36] efi/libstub: Disable -mbranch-protection In preparation for adding --orphan-handling=warn to more architectures, disable -mbranch-protection, as EFI does not yet support it[1]. This was noticed due to it producing unwanted .note.gnu.property sections (prefixed with .init due to the objcopy build step). However, we must also work around a bug in Clang where the section is still emitted for code-less object files[2], so also remove the section during the objcopy. [1] https://lore.kernel.org/lkml/CAMj1kXHck12juGi=E=P4hWP_8vQhQ+-x3vBMc3TGeRWdQ-XkxQ@mail.gmail.com [2] https://bugs.llvm.org/show_bug.cgi?id=46480 Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Reviewed-by: Nick Desaulniers Acked-by: Ard Biesheuvel Link: https://lore.kernel.org/r/20200821194310.3089815-8-keescook@chromium.org --- drivers/firmware/efi/libstub/Makefile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 5eefd60917df..0c911e391d75 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -18,7 +18,8 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ \ # arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly # disable the stackleak plugin cflags-$(CONFIG_ARM64) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \ - -fpie $(DISABLE_STACKLEAK_PLUGIN) + -fpie $(DISABLE_STACKLEAK_PLUGIN) \ + $(call cc-option,-mbranch-protection=none) cflags-$(CONFIG_ARM) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \ -fno-builtin -fpic \ $(call cc-option,-mno-single-pic-base) @@ -66,6 +67,12 @@ lib-$(CONFIG_X86) += x86-stub.o CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) +# Even when -mbranch-protection=none is set, Clang will generate a +# .note.gnu.property for code-less object files (like lib/ctype.c), +# so work around this by explicitly removing the unwanted section. +# https://bugs.llvm.org/show_bug.cgi?id=46480 +STUBCOPY_FLAGS-y += --remove-section=.note.gnu.property + # # For x86, bootloaders like systemd-boot or grub-efi do not zero-initialize the # .bss section, so the .bss section of the EFI stub needs to be included in the From b4ca91027d8226ae423ce498f03f5b348cf84e36 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:49 -0700 Subject: [PATCH 15/36] arm64/mm: Remove needless section quotes Fix a case of needless quotes in __section(), which Clang doesn't like. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Reviewed-by: Nick Desaulniers Acked-by: Will Deacon Link: https://lore.kernel.org/r/20200821194310.3089815-9-keescook@chromium.org --- arch/arm64/mm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 75df62fea1b6..e43c805b7b8c 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -43,7 +43,7 @@ u64 idmap_t0sz = TCR_T0SZ(VA_BITS); u64 idmap_ptrs_per_pgd = PTRS_PER_PGD; -u64 __section(".mmuoff.data.write") vabits_actual; +u64 __section(.mmuoff.data.write) vabits_actual; EXPORT_SYMBOL(vabits_actual); u64 kimage_voffset __ro_after_init; From 34b4a5c54c429d12bcc783a27650752237c49a36 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:50 -0700 Subject: [PATCH 16/36] arm64/kernel: Remove needless Call Frame Information annotations Remove last instance of an .eh_frame section by removing the needless Call Frame Information annotations which were likely leftovers from 32-bit ARM. Suggested-by: Ard Biesheuvel Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Acked-by: Will Deacon Link: https://lore.kernel.org/r/20200821194310.3089815-10-keescook@chromium.org --- arch/arm64/kernel/smccc-call.S | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/kernel/smccc-call.S b/arch/arm64/kernel/smccc-call.S index 1f93809528a4..d62447964ed9 100644 --- a/arch/arm64/kernel/smccc-call.S +++ b/arch/arm64/kernel/smccc-call.S @@ -9,7 +9,6 @@ #include .macro SMCCC instr - .cfi_startproc \instr #0 ldr x4, [sp] stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS] @@ -21,7 +20,6 @@ b.ne 1f str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS] 1: ret - .cfi_endproc .endm /* From 6e0a66d10c5b629369afa47b753d0ec46fa812dd Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:51 -0700 Subject: [PATCH 17/36] arm64/build: Remove .eh_frame* sections due to unwind tables Avoid .eh_frame* section generation by making sure both CFLAGS and AFLAGS contain -fno-asychronous-unwind-tables and -fno-unwind-tables. With all sources of .eh_frame now removed from the build, drop this DISCARD so we can be alerted in the future if it returns unexpectedly once orphan section warnings have been enabled. Suggested-by: Ard Biesheuvel Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Acked-by: Will Deacon Link: https://lore.kernel.org/r/20200821194310.3089815-11-keescook@chromium.org --- arch/arm64/Makefile | 5 ++++- arch/arm64/kernel/vmlinux.lds.S | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 55bc8546d9c7..6de7f551b821 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -47,13 +47,16 @@ endif KBUILD_CFLAGS += -mgeneral-regs-only \ $(compat_vdso) $(cc_has_k_constraint) -KBUILD_CFLAGS += -fno-asynchronous-unwind-tables KBUILD_CFLAGS += $(call cc-disable-warning, psabi) KBUILD_AFLAGS += $(compat_vdso) KBUILD_CFLAGS += $(call cc-option,-mabi=lp64) KBUILD_AFLAGS += $(call cc-option,-mabi=lp64) +# Avoid generating .eh_frame* sections. +KBUILD_CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables +KBUILD_AFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables + ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y) prepare: stack_protector_prepare stack_protector_prepare: prepare0 diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 13fc2ec46aae..c2b8426bf4bd 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -94,7 +94,6 @@ SECTIONS *(.discard.*) *(.interp .dynamic) *(.dynsym .dynstr .hash .gnu.hash) - *(.eh_frame) } . = KIMAGE_VADDR + TEXT_OFFSET; From 2883352bf801d093a04f269800b48bb8aa2515fb Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:52 -0700 Subject: [PATCH 18/36] arm64/build: Use common DISCARDS in linker script Use the common DISCARDS rule for the linker script in an effort to regularize the linker script to prepare for warning on orphaned sections. Additionally clean up left-over no-op macros. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Acked-by: Will Deacon Link: https://lore.kernel.org/r/20200821194310.3089815-12-keescook@chromium.org --- arch/arm64/kernel/vmlinux.lds.S | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index c2b8426bf4bd..082e9efa2b43 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -6,6 +6,7 @@ */ #define RO_EXCEPTION_TABLE_ALIGN 8 +#define RUNTIME_DISCARD_EXIT #include #include @@ -88,10 +89,8 @@ SECTIONS * matching the same input section name. There is no documented * order of matching. */ + DISCARDS /DISCARD/ : { - EXIT_CALL - *(.discard) - *(.discard.*) *(.interp .dynamic) *(.dynsym .dynstr .hash .gnu.hash) } From 578d7f0fd6a5ec8a369a4537c664eb2c8374c134 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:53 -0700 Subject: [PATCH 19/36] arm64/build: Add missing DWARF sections Explicitly include DWARF sections when they're present in the build. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Cc: Catalin Marinas Cc: Will Deacon Link: https://lore.kernel.org/r/20200821194310.3089815-13-keescook@chromium.org --- arch/arm64/kernel/vmlinux.lds.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 082e9efa2b43..16eb2ef806cd 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -239,6 +239,7 @@ SECTIONS _end = .; STABS_DEBUG + DWARF_DEBUG ELF_DETAILS HEAD_SYMBOLS From be2881824ae9eb92a35b094f734f9ca7339ddf6d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:54 -0700 Subject: [PATCH 20/36] arm64/build: Assert for unwanted sections In preparation for warning on orphan sections, discard unwanted non-zero-sized generated sections, and enforce other expected-to-be-zero-sized sections (since discarding them might hide problems with them suddenly gaining unexpected entries). Suggested-by: Ard Biesheuvel Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Cc: Catalin Marinas Cc: Will Deacon Link: https://lore.kernel.org/r/20200821194310.3089815-14-keescook@chromium.org --- arch/arm64/kernel/vmlinux.lds.S | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 16eb2ef806cd..e8847ca6a945 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -121,6 +121,14 @@ SECTIONS *(.got) /* Global offset table */ } + /* + * Make sure that the .got.plt is either completely empty or it + * contains only the lazy dispatch entries. + */ + .got.plt : { *(.got.plt) } + ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18, + "Unexpected GOT/PLT entries detected!") + . = ALIGN(SEGMENT_ALIGN); _etext = .; /* End of text section */ @@ -243,6 +251,18 @@ SECTIONS ELF_DETAILS HEAD_SYMBOLS + + /* + * Sections that should stay zero sized, which is safer to + * explicitly check instead of blindly discarding. + */ + .plt : { + *(.plt) *(.plt.*) *(.iplt) *(.igot) + } + ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!") + + .data.rel.ro : { *(.data.rel.ro) } + ASSERT(SIZEOF(.data.rel.ro) == 0, "Unexpected RELRO detected!") } #include "image-vars.h" From d7e3b065dc98e95f2dae6d2da031dd4c243bd7be Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:56 -0700 Subject: [PATCH 21/36] arm/build: Refactor linker script headers In preparation for adding --orphan-handling=warn, refactor the linker script header includes, and extract common macros. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Cc: Russell King Link: https://lore.kernel.org/r/20200821194310.3089815-16-keescook@chromium.org --- arch/arm/{kernel => include/asm}/vmlinux.lds.h | 13 ++++++++----- arch/arm/kernel/vmlinux-xip.lds.S | 4 +--- arch/arm/kernel/vmlinux.lds.S | 4 +--- 3 files changed, 10 insertions(+), 11 deletions(-) rename arch/arm/{kernel => include/asm}/vmlinux.lds.h (96%) diff --git a/arch/arm/kernel/vmlinux.lds.h b/arch/arm/include/asm/vmlinux.lds.h similarity index 96% rename from arch/arm/kernel/vmlinux.lds.h rename to arch/arm/include/asm/vmlinux.lds.h index 381a8e105fa5..a08f4301b718 100644 --- a/arch/arm/kernel/vmlinux.lds.h +++ b/arch/arm/include/asm/vmlinux.lds.h @@ -1,4 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#include #ifdef CONFIG_HOTPLUG_CPU #define ARM_CPU_DISCARD(x) @@ -49,8 +50,12 @@ EXIT_CALL \ ARM_MMU_DISCARD(*(.text.fixup)) \ ARM_MMU_DISCARD(*(__ex_table)) \ - *(.discard) \ - *(.discard.*) + COMMON_DISCARDS + +#define ARM_STUBS_TEXT \ + *(.gnu.warning) \ + *(.glue_7) \ + *(.glue_7t) #define ARM_TEXT \ IDMAP_TEXT \ @@ -64,9 +69,7 @@ CPUIDLE_TEXT \ LOCK_TEXT \ KPROBES_TEXT \ - *(.gnu.warning) \ - *(.glue_7) \ - *(.glue_7t) \ + ARM_STUBS_TEXT \ . = ALIGN(4); \ *(.got) /* Global offset table */ \ ARM_CPU_KEEP(PROC_INFO) diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S index 3d4e88f08196..904c31fa20ed 100644 --- a/arch/arm/kernel/vmlinux-xip.lds.S +++ b/arch/arm/kernel/vmlinux-xip.lds.S @@ -9,15 +9,13 @@ #include -#include +#include #include #include #include #include #include -#include "vmlinux.lds.h" - OUTPUT_ARCH(arm) ENTRY(stext) diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 5592f14b7e35..bb950c896a67 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -9,15 +9,13 @@ #else #include -#include +#include #include #include #include #include #include -#include "vmlinux.lds.h" - OUTPUT_ARCH(arm) ENTRY(stext) From 3b14aefb84320ac430cecbdc87b680317916b2bd Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:57 -0700 Subject: [PATCH 22/36] arm/build: Explicitly keep .ARM.attributes sections In preparation for adding --orphan-handling=warn, explicitly keep the .ARM.attributes section (at address 0[1]) by expanding the existing ELF_DETAILS macro into ARM_DETAILS. [1] https://reviews.llvm.org/D85867 Suggested-by: Nick Desaulniers Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Reviewed-by: Fangrui Song Cc: Russell King Link: https://lore.kernel.org/lkml/CAKwvOdk-racgq5pxsoGS6Vtifbtrk5fmkmnoLxrQMaOvV0nPWw@mail.gmail.com/ Link: https://lore.kernel.org/r/20200821194310.3089815-17-keescook@chromium.org --- arch/arm/include/asm/vmlinux.lds.h | 4 ++++ arch/arm/kernel/vmlinux-xip.lds.S | 2 +- arch/arm/kernel/vmlinux.lds.S | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/vmlinux.lds.h b/arch/arm/include/asm/vmlinux.lds.h index a08f4301b718..c4af5182ab48 100644 --- a/arch/arm/include/asm/vmlinux.lds.h +++ b/arch/arm/include/asm/vmlinux.lds.h @@ -52,6 +52,10 @@ ARM_MMU_DISCARD(*(__ex_table)) \ COMMON_DISCARDS +#define ARM_DETAILS \ + ELF_DETAILS \ + .ARM.attributes 0 : { *(.ARM.attributes) } + #define ARM_STUBS_TEXT \ *(.gnu.warning) \ *(.glue_7) \ diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S index 904c31fa20ed..57fcbf55f913 100644 --- a/arch/arm/kernel/vmlinux-xip.lds.S +++ b/arch/arm/kernel/vmlinux-xip.lds.S @@ -150,7 +150,7 @@ SECTIONS _end = .; STABS_DEBUG - ELF_DETAILS + ARM_DETAILS } /* diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index bb950c896a67..1d3d3b599635 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -149,7 +149,7 @@ SECTIONS _end = .; STABS_DEBUG - ELF_DETAILS + ARM_DETAILS } #ifdef CONFIG_STRICT_KERNEL_RWX From 512dd2eebe5585893412e0c8bec8dbfe2dead6c8 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:58 -0700 Subject: [PATCH 23/36] arm/build: Add missing sections Add missing text stub sections .vfp11_veneer and .v4_bx, as well as missing DWARF sections, when present in the build. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Reviewed-by: Nick Desaulniers Cc: Russell King Link: https://lore.kernel.org/r/20200821194310.3089815-18-keescook@chromium.org --- arch/arm/include/asm/vmlinux.lds.h | 4 +++- arch/arm/kernel/vmlinux-xip.lds.S | 1 + arch/arm/kernel/vmlinux.lds.S | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/vmlinux.lds.h b/arch/arm/include/asm/vmlinux.lds.h index c4af5182ab48..6624dd97475c 100644 --- a/arch/arm/include/asm/vmlinux.lds.h +++ b/arch/arm/include/asm/vmlinux.lds.h @@ -59,7 +59,9 @@ #define ARM_STUBS_TEXT \ *(.gnu.warning) \ *(.glue_7) \ - *(.glue_7t) + *(.glue_7t) \ + *(.vfp11_veneer) \ + *(.v4_bx) #define ARM_TEXT \ IDMAP_TEXT \ diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S index 57fcbf55f913..11ffa79751da 100644 --- a/arch/arm/kernel/vmlinux-xip.lds.S +++ b/arch/arm/kernel/vmlinux-xip.lds.S @@ -150,6 +150,7 @@ SECTIONS _end = .; STABS_DEBUG + DWARF_DEBUG ARM_DETAILS } diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 1d3d3b599635..dc672fe35de3 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -149,6 +149,7 @@ SECTIONS _end = .; STABS_DEBUG + DWARF_DEBUG ARM_DETAILS } From 0c918e753f8c03b0308a635c0721a8c24d738d4a Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:42:59 -0700 Subject: [PATCH 24/36] arm/build: Assert for unwanted sections In preparation for warning on orphan sections, enforce expected-to-be-zero-sized sections (since discarding them might hide problems with them suddenly gaining unexpected entries). Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Cc: Russell King Link: https://lore.kernel.org/r/20200821194310.3089815-19-keescook@chromium.org --- arch/arm/include/asm/vmlinux.lds.h | 11 +++++++++++ arch/arm/kernel/vmlinux-xip.lds.S | 2 ++ arch/arm/kernel/vmlinux.lds.S | 2 ++ 3 files changed, 15 insertions(+) diff --git a/arch/arm/include/asm/vmlinux.lds.h b/arch/arm/include/asm/vmlinux.lds.h index 6624dd97475c..4a91428c324d 100644 --- a/arch/arm/include/asm/vmlinux.lds.h +++ b/arch/arm/include/asm/vmlinux.lds.h @@ -52,6 +52,17 @@ ARM_MMU_DISCARD(*(__ex_table)) \ COMMON_DISCARDS +/* + * Sections that should stay zero sized, which is safer to explicitly + * check instead of blindly discarding. + */ +#define ARM_ASSERTS \ + .plt : { \ + *(.iplt) *(.rel.iplt) *(.iplt) *(.igot.plt) \ + } \ + ASSERT(SIZEOF(.plt) == 0, \ + "Unexpected run-time procedure linkages detected!") + #define ARM_DETAILS \ ELF_DETAILS \ .ARM.attributes 0 : { *(.ARM.attributes) } diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S index 11ffa79751da..50136828f5b5 100644 --- a/arch/arm/kernel/vmlinux-xip.lds.S +++ b/arch/arm/kernel/vmlinux-xip.lds.S @@ -152,6 +152,8 @@ SECTIONS STABS_DEBUG DWARF_DEBUG ARM_DETAILS + + ARM_ASSERTS } /* diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index dc672fe35de3..5f4922e858d0 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -151,6 +151,8 @@ SECTIONS STABS_DEBUG DWARF_DEBUG ARM_DETAILS + + ARM_ASSERTS } #ifdef CONFIG_STRICT_KERNEL_RWX From 7e8c4ed2638d08a1604c87b60ed7161bf92e6f86 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:43:01 -0700 Subject: [PATCH 25/36] arm/boot: Handle all sections explicitly In preparation for warning on orphan sections, use common macros for debug sections, discards, and text stubs. Add discards for unwanted .note, and .rel sections. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Cc: Russell King Link: https://lore.kernel.org/r/20200821194310.3089815-21-keescook@chromium.org --- arch/arm/boot/compressed/vmlinux.lds.S | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S index 09ac33f52814..b914be3a207b 100644 --- a/arch/arm/boot/compressed/vmlinux.lds.S +++ b/arch/arm/boot/compressed/vmlinux.lds.S @@ -2,6 +2,7 @@ /* * Copyright (C) 2000 Russell King */ +#include #ifdef CONFIG_CPU_ENDIAN_BE8 #define ZIMAGE_MAGIC(x) ( (((x) >> 24) & 0x000000ff) | \ @@ -17,8 +18,11 @@ ENTRY(_start) SECTIONS { /DISCARD/ : { + COMMON_DISCARDS *(.ARM.exidx*) *(.ARM.extab*) + *(.note.*) + *(.rel.*) /* * Discard any r/w data - this produces a link error if we have any, * which is required for PIC decompression. Local data generates @@ -36,9 +40,7 @@ SECTIONS *(.start) *(.text) *(.text.*) - *(.gnu.warning) - *(.glue_7t) - *(.glue_7) + ARM_STUBS_TEXT } .table : ALIGN(4) { _table_start = .; @@ -128,12 +130,10 @@ SECTIONS PROVIDE(__pecoff_data_size = ALIGN(512) - ADDR(.data)); PROVIDE(__pecoff_end = ALIGN(512)); - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } + STABS_DEBUG + DWARF_DEBUG + ARM_DETAILS + + ARM_ASSERTS } ASSERT(_edata_real == _edata, "error: zImage file size is incorrect"); From a850958c072404f75dd41782cb4ff34b8625b47d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:43:03 -0700 Subject: [PATCH 26/36] x86/asm: Avoid generating unused kprobe sections When !CONFIG_KPROBES, do not generate kprobe sections. This makes sure there are no unexpected sections encountered by the linker scripts. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Link: https://lore.kernel.org/r/20200821194310.3089815-23-keescook@chromium.org --- arch/x86/include/asm/asm.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index 5c15f95b1ba7..4712206c4325 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -138,11 +138,15 @@ # define _ASM_EXTABLE_FAULT(from, to) \ _ASM_EXTABLE_HANDLE(from, to, ex_handler_fault) -# define _ASM_NOKPROBE(entry) \ +# ifdef CONFIG_KPROBES +# define _ASM_NOKPROBE(entry) \ .pushsection "_kprobe_blacklist","aw" ; \ _ASM_ALIGN ; \ _ASM_PTR (entry); \ .popsection +# else +# define _ASM_NOKPROBE(entry) +# endif #else /* ! __ASSEMBLY__ */ # define _EXPAND_EXTABLE_HANDLE(x) #x From 815d680771ae09080d2da83dac2647c08cdf99ce Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:43:04 -0700 Subject: [PATCH 27/36] x86/build: Enforce an empty .got.plt section The .got.plt section should always be zero (or filled only with the linker-generated lazy dispatch entry). Enforce this with an assert and mark the section as INFO. This is more sensitive than just blindly discarding the section. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Link: https://lore.kernel.org/r/20200821194310.3089815-24-keescook@chromium.org --- arch/x86/kernel/vmlinux.lds.S | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 0cc035cb15f1..4b1b936a6e7d 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -414,8 +414,20 @@ SECTIONS ELF_DETAILS DISCARDS -} + /* + * Make sure that the .got.plt is either completely empty or it + * contains only the lazy dispatch entries. + */ + .got.plt (INFO) : { *(.got.plt) } + ASSERT(SIZEOF(.got.plt) == 0 || +#ifdef CONFIG_X86_64 + SIZEOF(.got.plt) == 0x18, +#else + SIZEOF(.got.plt) == 0xc, +#endif + "Unexpected GOT/PLT entries detected!") +} #ifdef CONFIG_X86_32 /* From 5354e84598f264793265cc99b4be2a2295826c86 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:43:05 -0700 Subject: [PATCH 28/36] x86/build: Add asserts for unwanted sections In preparation for warning on orphan sections, enforce other expected-to-be-zero-sized sections (since discarding them might hide problems with them suddenly gaining unexpected entries). Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Link: https://lore.kernel.org/r/20200821194310.3089815-25-keescook@chromium.org --- arch/x86/kernel/vmlinux.lds.S | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 4b1b936a6e7d..45d72447df84 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -427,6 +427,30 @@ SECTIONS SIZEOF(.got.plt) == 0xc, #endif "Unexpected GOT/PLT entries detected!") + + /* + * Sections that should stay zero sized, which is safer to + * explicitly check instead of blindly discarding. + */ + .got : { + *(.got) *(.igot.*) + } + ASSERT(SIZEOF(.got) == 0, "Unexpected GOT entries detected!") + + .plt : { + *(.plt) *(.plt.*) *(.iplt) + } + ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!") + + .rel.dyn : { + *(.rel.*) *(.rel_*) + } + ASSERT(SIZEOF(.rel.dyn) == 0, "Unexpected run-time relocations (.rel) detected!") + + .rela.dyn : { + *(.rela.*) *(.rela_*) + } + ASSERT(SIZEOF(.rela.dyn) == 0, "Unexpected run-time relocations (.rela) detected!") } #ifdef CONFIG_X86_32 From 7cf891a40057f851af74e68bacb01b90bd775b5d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:43:07 -0700 Subject: [PATCH 29/36] x86/boot/compressed: Reorganize zero-size section asserts For readability, move the zero-sized sections to the end after DISCARDS. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Link: https://lore.kernel.org/r/20200821194310.3089815-27-keescook@chromium.org --- arch/x86/boot/compressed/vmlinux.lds.S | 44 +++++++++++++++----------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S index 3c2ee9a5bf43..ca544a16724b 100644 --- a/arch/x86/boot/compressed/vmlinux.lds.S +++ b/arch/x86/boot/compressed/vmlinux.lds.S @@ -42,19 +42,6 @@ SECTIONS *(.rodata.*) _erodata = . ; } - .rel.dyn : { - *(.rel.*) - } - .rela.dyn : { - *(.rela.*) - } - .got : { - *(.got) - } - .got.plt : { - *(.got.plt) - } - .data : { _data = . ; *(.data) @@ -85,13 +72,34 @@ SECTIONS ELF_DETAILS DISCARDS -} -ASSERT(SIZEOF(.got) == 0, "Unexpected GOT entries detected!") + .got.plt (INFO) : { + *(.got.plt) + } + ASSERT(SIZEOF(.got.plt) == 0 || #ifdef CONFIG_X86_64 -ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18, "Unexpected GOT/PLT entries detected!") + SIZEOF(.got.plt) == 0x18, #else -ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0xc, "Unexpected GOT/PLT entries detected!") + SIZEOF(.got.plt) == 0xc, #endif + "Unexpected GOT/PLT entries detected!") -ASSERT(SIZEOF(.rel.dyn) == 0 && SIZEOF(.rela.dyn) == 0, "Unexpected run-time relocations detected!") + /* + * Sections that should stay zero sized, which is safer to + * explicitly check instead of blindly discarding. + */ + .got : { + *(.got) + } + ASSERT(SIZEOF(.got) == 0, "Unexpected GOT entries detected!") + + .rel.dyn : { + *(.rel.*) + } + ASSERT(SIZEOF(.rel.dyn) == 0, "Unexpected run-time relocations (.rel) detected!") + + .rela.dyn : { + *(.rela.*) + } + ASSERT(SIZEOF(.rela.dyn) == 0, "Unexpected run-time relocations (.rela) detected!") +} From d1c0272bc1c068f8c2cb3d1b395173602b0df6e7 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:43:08 -0700 Subject: [PATCH 30/36] x86/boot/compressed: Remove, discard, or assert for unwanted sections In preparation for warning on orphan sections, stop the linker from generating the .eh_frame* sections, discard unwanted non-zero-sized generated sections, and enforce other expected-to-be-zero-sized sections (since discarding them might hide problems with them suddenly gaining unexpected entries). Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Link: https://lore.kernel.org/r/20200821194310.3089815-28-keescook@chromium.org --- arch/x86/boot/compressed/Makefile | 1 + arch/x86/boot/compressed/vmlinux.lds.S | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 753d57266757..5b7f6e175b03 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -50,6 +50,7 @@ GCOV_PROFILE := n UBSAN_SANITIZE :=n KBUILD_LDFLAGS := -m elf_$(UTS_MACHINE) +KBUILD_LDFLAGS += $(call ld-option,--no-ld-generated-unwind-info) # Compressed kernel should be built as PIE since it may be loaded at any # address by the bootloader. LDFLAGS_vmlinux := -pie $(call ld-option, --no-dynamic-linker) diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S index ca544a16724b..02f6feb0e55b 100644 --- a/arch/x86/boot/compressed/vmlinux.lds.S +++ b/arch/x86/boot/compressed/vmlinux.lds.S @@ -72,6 +72,11 @@ SECTIONS ELF_DETAILS DISCARDS + /DISCARD/ : { + *(.dynamic) *(.dynsym) *(.dynstr) *(.dynbss) + *(.hash) *(.gnu.hash) + *(.note.*) + } .got.plt (INFO) : { *(.got.plt) @@ -93,13 +98,18 @@ SECTIONS } ASSERT(SIZEOF(.got) == 0, "Unexpected GOT entries detected!") + .plt : { + *(.plt) *(.plt.*) + } + ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!") + .rel.dyn : { - *(.rel.*) + *(.rel.*) *(.rel_*) } ASSERT(SIZEOF(.rel.dyn) == 0, "Unexpected run-time relocations (.rel) detected!") .rela.dyn : { - *(.rela.*) + *(.rela.*) *(.rela_*) } ASSERT(SIZEOF(.rela.dyn) == 0, "Unexpected run-time relocations (.rela) detected!") } From 414d2ff5e5f21049b6b242271a6a8579f9dffc1b Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 21 Aug 2020 12:43:09 -0700 Subject: [PATCH 31/36] x86/boot/compressed: Add missing debugging sections to output Include the missing DWARF and STABS sections in the compressed image, when they are present. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Link: https://lore.kernel.org/r/20200821194310.3089815-29-keescook@chromium.org --- arch/x86/boot/compressed/vmlinux.lds.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S index 02f6feb0e55b..112b2375d021 100644 --- a/arch/x86/boot/compressed/vmlinux.lds.S +++ b/arch/x86/boot/compressed/vmlinux.lds.S @@ -69,6 +69,8 @@ SECTIONS . = ALIGN(PAGE_SIZE); /* keep ZO size page aligned */ _end = .; + STABS_DEBUG + DWARF_DEBUG ELF_DETAILS DISCARDS From b3e5d80d0c48c0cc7bce56473672f4e6e1210910 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 1 Sep 2020 19:53:43 -0700 Subject: [PATCH 32/36] arm64/build: Warn on orphan section placement We don't want to depend on the linker's orphan section placement heuristics as these can vary between linkers, and may change between versions. All sections need to be explicitly handled in the linker script. With all sections now handled, enable orphan section warnings. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Acked-by: Will Deacon Reviewed-by: Nick Desaulniers Link: https://lore.kernel.org/r/20200902025347.2504702-2-keescook@chromium.org --- arch/arm64/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 6de7f551b821..081144fcc3da 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -29,6 +29,10 @@ LDFLAGS_vmlinux += --fix-cortex-a53-843419 endif endif +# We never want expected sections to be placed heuristically by the +# linker. All sections should be explicitly named in the linker script. +LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn) + ifeq ($(CONFIG_ARM64_USE_LSE_ATOMICS), y) ifneq ($(CONFIG_ARM64_LSE_ATOMICS), y) $(warning LSE atomics not supported by binutils) From 5a17850e251a55bba6d65aefbfeacfa9888cd2cd Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 1 Sep 2020 19:53:44 -0700 Subject: [PATCH 33/36] arm/build: Warn on orphan section placement We don't want to depend on the linker's orphan section placement heuristics as these can vary between linkers, and may change between versions. All sections need to be explicitly handled in the linker script. Specifically, this would have made a recently fixed bug very obvious: ld: warning: orphan section `.fixup' from `arch/arm/lib/copy_from_user.o' being placed in section `.fixup' With all sections handled, enable orphan section warning. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Reviewed-by: Nick Desaulniers Link: https://lore.kernel.org/r/20200902025347.2504702-3-keescook@chromium.org --- arch/arm/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 4e877354515f..e589da3c8949 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -16,6 +16,10 @@ LDFLAGS_vmlinux += --be8 KBUILD_LDFLAGS_MODULE += --be8 endif +# We never want expected sections to be placed heuristically by the +# linker. All sections should be explicitly named in the linker script. +LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn) + ifeq ($(CONFIG_ARM_MODULE_PLTS),y) KBUILD_LDS_MODULE += $(srctree)/arch/arm/kernel/module.lds endif From 4409d2f8dfe7d5088567d4ba00133f876ee586c7 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 1 Sep 2020 19:53:45 -0700 Subject: [PATCH 34/36] arm/boot: Warn on orphan section placement We don't want to depend on the linker's orphan section placement heuristics as these can vary between linkers, and may change between versions. All sections need to be explicitly handled in the linker script. With all sections now handled, enable orphan section warning. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Reviewed-by: Nick Desaulniers Link: https://lore.kernel.org/r/20200902025347.2504702-4-keescook@chromium.org --- arch/arm/boot/compressed/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index b1147b7f2c8d..58028abd05d9 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -123,6 +123,8 @@ endif LDFLAGS_vmlinux += --no-undefined # Delete all temporary local symbols LDFLAGS_vmlinux += -X +# Report orphan sections +LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn) # Next argument is a linker script LDFLAGS_vmlinux += -T From 83109d5d5fba7abf362f5a443c9f4c4ea10bbc8d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 1 Sep 2020 19:53:46 -0700 Subject: [PATCH 35/36] x86/build: Warn on orphan section placement We don't want to depend on the linker's orphan section placement heuristics as these can vary between linkers, and may change between versions. All sections need to be explicitly handled in the linker script. Now that all sections are explicitly handled, enable orphan section warnings. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Reviewed-by: Nick Desaulniers Link: https://lore.kernel.org/r/20200902025347.2504702-5-keescook@chromium.org --- arch/x86/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 4346ffb2e39f..154259f18b8b 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -209,6 +209,10 @@ ifdef CONFIG_X86_64 LDFLAGS_vmlinux += -z max-page-size=0x200000 endif +# We never want expected sections to be placed heuristically by the +# linker. All sections should be explicitly named in the linker script. +LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn) + archscripts: scripts_basic $(Q)$(MAKE) $(build)=arch/x86/tools relocs From 6e0bf0e0e55000742a53c5f3b58f8669e0091a11 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 1 Sep 2020 19:53:47 -0700 Subject: [PATCH 36/36] x86/boot/compressed: Warn on orphan section placement We don't want to depend on the linker's orphan section placement heuristics as these can vary between linkers, and may change between versions. All sections need to be explicitly handled in the linker script. Now that all sections are explicitly handled, enable orphan section warnings. Signed-off-by: Kees Cook Signed-off-by: Ingo Molnar Reviewed-by: Nick Desaulniers Link: https://lore.kernel.org/r/20200902025347.2504702-6-keescook@chromium.org --- arch/x86/boot/compressed/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 5b7f6e175b03..871cc071c925 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -54,6 +54,7 @@ KBUILD_LDFLAGS += $(call ld-option,--no-ld-generated-unwind-info) # Compressed kernel should be built as PIE since it may be loaded at any # address by the bootloader. LDFLAGS_vmlinux := -pie $(call ld-option, --no-dynamic-linker) +LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn) LDFLAGS_vmlinux += -T hostprogs := mkpiggy