walters / rpms / kernel

Forked from rpms/kernel 5 years ago
Clone
168984b
From 6d92bc9d483aa1751755a66fee8fb39dffb088c0 Mon Sep 17 00:00:00 2001
168984b
From: "H.J. Lu" <hjl.tools@gmail.com>
168984b
Date: Wed, 16 Mar 2016 20:04:35 -0700
168984b
Subject: [PATCH] x86/build: Build compressed x86 kernels as PIE
168984b
168984b
The 32-bit x86 assembler in binutils 2.26 will generate R_386_GOT32X
168984b
relocation to get the symbol address in PIC.  When the compressed x86
168984b
kernel isn't built as PIC, the linker optimizes R_386_GOT32X relocations
168984b
to their fixed symbol addresses.  However, when the compressed x86
168984b
kernel is loaded at a different address, it leads to the following
168984b
load failure:
168984b
168984b
  Failed to allocate space for phdrs
168984b
168984b
during the decompression stage.
168984b
168984b
If the compressed x86 kernel is relocatable at run-time, it should be
168984b
compiled with -fPIE, instead of -fPIC, if possible and should be built as
168984b
Position Independent Executable (PIE) so that linker won't optimize
168984b
R_386_GOT32X relocation to its fixed symbol address.
168984b
168984b
Older linkers generate R_386_32 relocations against locally defined
168984b
symbols, _bss, _ebss, _got and _egot, in PIE.  It isn't wrong, just less
168984b
optimal than R_386_RELATIVE.  But the x86 kernel fails to properly handle
168984b
R_386_32 relocations when relocating the kernel.  To generate
168984b
R_386_RELATIVE relocations, we mark _bss, _ebss, _got and _egot as
168984b
hidden in both 32-bit and 64-bit x86 kernels.
168984b
168984b
To build a 64-bit compressed x86 kernel as PIE, we need to disable the
168984b
relocation overflow check to avoid relocation overflow errors. We do
168984b
this with a new linker command-line option, -z noreloc-overflow, which
168984b
got added recently:
168984b
168984b
 commit 4c10bbaa0912742322f10d9d5bb630ba4e15dfa7
168984b
 Author: H.J. Lu <hjl.tools@gmail.com>
168984b
 Date:   Tue Mar 15 11:07:06 2016 -0700
168984b
168984b
    Add -z noreloc-overflow option to x86-64 ld
168984b
168984b
    Add -z noreloc-overflow command-line option to the x86-64 ELF linker to
168984b
    disable relocation overflow check.  This can be used to avoid relocation
168984b
    overflow check if there will be no dynamic relocation overflow at
168984b
    run-time.
168984b
168984b
The 64-bit compressed x86 kernel is built as PIE only if the linker supports
168984b
-z noreloc-overflow.  So far 64-bit relocatable compressed x86 kernel
168984b
boots fine even when it is built as a normal executable.
168984b
168984b
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
168984b
Cc: Andy Lutomirski <luto@amacapital.net>
168984b
Cc: Borislav Petkov <bp@alien8.de>
168984b
Cc: Brian Gerst <brgerst@gmail.com>
168984b
Cc: Denys Vlasenko <dvlasenk@redhat.com>
168984b
Cc: H. Peter Anvin <hpa@zytor.com>
168984b
Cc: Linus Torvalds <torvalds@linux-foundation.org>
168984b
Cc: Peter Zijlstra <peterz@infradead.org>
168984b
Cc: Thomas Gleixner <tglx@linutronix.de>
168984b
Cc: linux-kernel@vger.kernel.org
168984b
[ Edited the changelog and comments. ]
168984b
Signed-off-by: Ingo Molnar <mingo@kernel.org>
168984b
---
168984b
 arch/x86/boot/compressed/Makefile  | 14 +++++++++++++-
168984b
 arch/x86/boot/compressed/head_32.S | 28 ++++++++++++++++++++++++++++
168984b
 arch/x86/boot/compressed/head_64.S |  8 ++++++++
168984b
 3 files changed, 49 insertions(+), 1 deletion(-)
168984b
168984b
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
168984b
index 6915ff2..8774cb2 100644
168984b
--- a/arch/x86/boot/compressed/Makefile
168984b
+++ b/arch/x86/boot/compressed/Makefile
168984b
@@ -26,7 +26,7 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
168984b
 	vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4
168984b
168984b
 KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
168984b
-KBUILD_CFLAGS += -fno-strict-aliasing -fPIC
168984b
+KBUILD_CFLAGS += -fno-strict-aliasing $(call cc-option, -fPIE, -fPIC)
168984b
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
168984b
 cflags-$(CONFIG_X86_32) := -march=i386
168984b
 cflags-$(CONFIG_X86_64) := -mcmodel=small
168984b
@@ -40,6 +40,18 @@ GCOV_PROFILE := n
168984b
 UBSAN_SANITIZE :=n
168984b
168984b
 LDFLAGS := -m elf_$(UTS_MACHINE)
168984b
+ifeq ($(CONFIG_RELOCATABLE),y)
168984b
+# If kernel is relocatable, build compressed kernel as PIE.
168984b
+ifeq ($(CONFIG_X86_32),y)
168984b
+LDFLAGS += $(call ld-option, -pie) $(call ld-option, --no-dynamic-linker)
168984b
+else
168984b
+# To build 64-bit compressed kernel as PIE, we disable relocation
168984b
+# overflow check to avoid relocation overflow error with a new linker
168984b
+# command-line option, -z noreloc-overflow.
168984b
+LDFLAGS += $(shell $(LD) --help 2>&1 | grep -q "\-z noreloc-overflow" \
168984b
+	&& echo "-z noreloc-overflow -pie --no-dynamic-linker")
168984b
+endif
168984b
+endif
168984b
 LDFLAGS_vmlinux := -T
168984b
168984b
 hostprogs-y	:= mkpiggy
168984b
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
168984b
index 8ef964d..0256064 100644
168984b
--- a/arch/x86/boot/compressed/head_32.S
168984b
+++ b/arch/x86/boot/compressed/head_32.S
168984b
@@ -31,6 +31,34 @@
168984b
 #include <asm/asm-offsets.h>
168984b
 #include <asm/bootparam.h>
168984b
168984b
+/*
168984b
+ * The 32-bit x86 assembler in binutils 2.26 will generate R_386_GOT32X
168984b
+ * relocation to get the symbol address in PIC.  When the compressed x86
168984b
+ * kernel isn't built as PIC, the linker optimizes R_386_GOT32X
168984b
+ * relocations to their fixed symbol addresses.  However, when the
168984b
+ * compressed x86 kernel is loaded at a different address, it leads
168984b
+ * to the following load failure:
168984b
+ *
168984b
+ *   Failed to allocate space for phdrs
168984b
+ *
168984b
+ * during the decompression stage.
168984b
+ *
168984b
+ * If the compressed x86 kernel is relocatable at run-time, it should be
168984b
+ * compiled with -fPIE, instead of -fPIC, if possible and should be built as
168984b
+ * Position Independent Executable (PIE) so that linker won't optimize
168984b
+ * R_386_GOT32X relocation to its fixed symbol address.  Older
168984b
+ * linkers generate R_386_32 relocations against locally defined symbols,
168984b
+ * _bss, _ebss, _got and _egot, in PIE.  It isn't wrong, just less
168984b
+ * optimal than R_386_RELATIVE.  But the x86 kernel fails to properly handle
168984b
+ * R_386_32 relocations when relocating the kernel.  To generate
168984b
+ * R_386_RELATIVE relocations, we mark _bss, _ebss, _got and _egot as
168984b
+ * hidden:
168984b
+ */
168984b
+	.hidden _bss
168984b
+	.hidden _ebss
168984b
+	.hidden _got
168984b
+	.hidden _egot
168984b
+
168984b
 	__HEAD
168984b
 ENTRY(startup_32)
168984b
 #ifdef CONFIG_EFI_STUB
168984b
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
168984b
index b0c0d16..86558a1 100644
168984b
--- a/arch/x86/boot/compressed/head_64.S
168984b
+++ b/arch/x86/boot/compressed/head_64.S
168984b
@@ -33,6 +33,14 @@
168984b
 #include <asm/asm-offsets.h>
168984b
 #include <asm/bootparam.h>
168984b
168984b
+/*
168984b
+ * Locally defined symbols should be marked hidden:
168984b
+ */
168984b
+	.hidden _bss
168984b
+	.hidden _ebss
168984b
+	.hidden _got
168984b
+	.hidden _egot
168984b
+
168984b
 	__HEAD
168984b
 	.code32
168984b
 ENTRY(startup_32)
168984b
-- 
168984b
2.7.3
168984b