lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Mon, 26 Feb 2024 22:36:09 +0800
From: Lai Jiangshan <jiangshanlai@...il.com>
To: linux-kernel@...r.kernel.org
Cc: Hou Wenlong <houwenlong.hwl@...group.com>,
	Lai Jiangshan <jiangshan.ljs@...group.com>,
	Linus Torvalds <torvalds@...ux-foundation.org>,
	Peter Zijlstra <peterz@...radead.org>,
	Sean Christopherson <seanjc@...gle.com>,
	Thomas Gleixner <tglx@...utronix.de>,
	Borislav Petkov <bp@...en8.de>,
	Ingo Molnar <mingo@...hat.com>,
	kvm@...r.kernel.org,
	Paolo Bonzini <pbonzini@...hat.com>,
	x86@...nel.org,
	Kees Cook <keescook@...omium.org>,
	Juergen Gross <jgross@...e.com>,
	Dave Hansen <dave.hansen@...ux.intel.com>,
	"H. Peter Anvin" <hpa@...or.com>,
	Petr Pavlu <petr.pavlu@...e.com>,
	Josh Poimboeuf <jpoimboe@...nel.org>,
	Nick Desaulniers <ndesaulniers@...gle.com>
Subject: [RFC PATCH 52/73] x86/boot: Allow to do relocation for uncompressed kernel

From: Hou Wenlong <houwenlong.hwl@...group.com>

Relocation is currently only performed during the uncompression process.
However, in some situations, such as with security containers, the
uncompressed kernel can be booted directly. Therefore, it is useful to
allow for relocation of the uncompressed kernel. Taking inspiration from
the implementation in MIPS, a new section named ".data.relocs" is
reserved for relocations. The relocs tool can then append the
relocations into this section. Additionally, a helper function is
introduced to perform relocations during booting, similar to the
relocations in the bootloader. For PVH entry, relocation for the
pre-constructed page table should not be performed; otherwise, booting
will fail.

Signed-off-by: Hou Wenlong <houwenlong.hwl@...group.com>
Signed-off-by: Lai Jiangshan <jiangshan.ljs@...group.com>
---
 arch/x86/Kconfig                  | 20 +++++++++
 arch/x86/Makefile.postlink        |  9 +++-
 arch/x86/kernel/head64_identity.c | 70 +++++++++++++++++++++++++++++++
 arch/x86/kernel/vmlinux.lds.S     | 18 ++++++++
 4 files changed, 116 insertions(+), 1 deletion(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index a53b65499951..d02ef3bdb171 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2183,6 +2183,26 @@ config RELOCATABLE
 	  it has been loaded at and the compile time physical address
 	  (CONFIG_PHYSICAL_START) is used as the minimum location.
 
+config RELOCATABLE_UNCOMPRESSED_KERNEL
+	bool
+	depends on RELOCATABLE
+	help
+	  A table of relocation data will be appended to the uncompressed
+	  kernel binary and parsed at boot to fix up the relocated kernel.
+
+config RELOCATION_TABLE_SIZE
+	hex "Relocation table size"
+	depends on RELOCATABLE_UNCOMPRESSED_KERNEL
+	range 0x0 0x01000000
+	default "0x00200000"
+	help
+	  This option allows the amount of space reserved for the table to be
+	  adjusted, although the default of 1Mb should be ok in most cases.
+
+	  The build will fail and a valid size suggested if this is too small.
+
+	  If unsure, leave at the default value.
+
 config X86_PIE
 	bool "Build a PIE kernel"
 	default n
diff --git a/arch/x86/Makefile.postlink b/arch/x86/Makefile.postlink
index fef2e977cc7d..c115692b67b2 100644
--- a/arch/x86/Makefile.postlink
+++ b/arch/x86/Makefile.postlink
@@ -4,7 +4,8 @@
 # ===========================================================================
 #
 # 1. Separate relocations from vmlinux into vmlinux.relocs.
-# 2. Strip relocations from vmlinux.
+# 2. Insert relocations table into vmlinux
+# 3. Strip relocations from vmlinux.
 
 PHONY := __archpost
 __archpost:
@@ -20,6 +21,9 @@ quiet_cmd_relocs = RELOCS  $(OUT_RELOCS)/$@...locs
 	$(CMD_RELOCS) $@ > $(OUT_RELOCS)/$@...locs; \
 	$(CMD_RELOCS) --abs-relocs $@
 
+quiet_cmd_insert_relocs = RELOCS  $@
+      cmd_insert_relocs = $(CMD_RELOCS) --keep $@
+
 quiet_cmd_strip_relocs = RSTRIP  $@
       cmd_strip_relocs = \
 	$(OBJCOPY) --remove-section='.rel.*' --remove-section='.rel__*' \
@@ -29,6 +33,9 @@ quiet_cmd_strip_relocs = RSTRIP  $@
 
 vmlinux: FORCE
 	@true
+ifeq ($(CONFIG_RELOCATABLE_UNCOMPRESSED_KERNEL),y)
+	$(call cmd,insert_relocs)
+endif
 ifeq ($(CONFIG_X86_NEED_RELOCS),y)
 	$(call cmd,relocs)
 	$(call cmd,strip_relocs)
diff --git a/arch/x86/kernel/head64_identity.c b/arch/x86/kernel/head64_identity.c
index ecac6e704868..4548ad615ecf 100644
--- a/arch/x86/kernel/head64_identity.c
+++ b/arch/x86/kernel/head64_identity.c
@@ -315,3 +315,73 @@ void __head startup_64_setup_env(void)
 
 	startup_64_load_idt();
 }
+
+#ifdef CONFIG_RELOCATABLE_UNCOMPRESSED_KERNEL
+extern u8 __relocation_end[];
+
+static bool __head is_in_pvh_pgtable(unsigned long ptr)
+{
+#ifdef CONFIG_PVH
+	if (ptr >= (unsigned long)init_top_pgt &&
+	    ptr < (unsigned long)init_top_pgt + PAGE_SIZE)
+		return true;
+	if (ptr >= (unsigned long)level3_ident_pgt &&
+	    ptr < (unsigned long)level3_ident_pgt + PAGE_SIZE)
+		return true;
+#endif
+	return false;
+}
+
+void __head __relocate_kernel(unsigned long physbase, unsigned long virtbase)
+{
+	int *reloc = (int *)__relocation_end;
+	unsigned long ptr;
+	unsigned long delta = virtbase - __START_KERNEL_map;
+	unsigned long map = physbase - __START_KERNEL;
+	long extended;
+
+	/*
+	 * Relocation had happended in bootloader,
+	 * don't do it again.
+	 */
+	if (SYM_ABS_VA(_text) != __START_KERNEL)
+		return;
+
+	if (!delta)
+		return;
+
+	/*
+	 * Format is:
+	 *
+	 * kernel bits...
+	 * 0 - zero terminator for 64 bit relocations
+	 * 64 bit relocation repeated
+	 * 0 - zero terminator for inverse 32 bit relocations
+	 * 32 bit inverse relocation repeated
+	 * 0 - zero terminator for 32 bit relocations
+	 * 32 bit relocation repeated
+	 *
+	 * So we work backwards from the end of .data.relocs section, see
+	 * handle_relocations() in arch/x86/boot/compressed/misc.c.
+	 */
+	while (*--reloc) {
+		extended = *reloc;
+		ptr = (unsigned long)(extended + map);
+		*(uint32_t *)ptr += delta;
+	}
+
+	while (*--reloc) {
+		extended = *reloc;
+		ptr = (unsigned long)(extended + map);
+		*(int32_t *)ptr -= delta;
+	}
+
+	while (*--reloc) {
+		extended = *reloc;
+		ptr = (unsigned long)(extended + map);
+		if (is_in_pvh_pgtable(ptr))
+			continue;
+		*(uint64_t *)ptr += delta;
+	}
+}
+#endif
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 834c68b45f15..3b05807fe1dc 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -339,6 +339,24 @@ SECTIONS
 	}
 #endif
 
+#ifdef CONFIG_RELOCATABLE_UNCOMPRESSED_KERNEL
+	. = ALIGN(4);
+	.data.reloc : AT(ADDR(.data.reloc) - LOAD_OFFSET) {
+		__relocation_start = .;
+		/*
+		 * Space for relocation table
+		 * This needs to be filled so that the
+		 * relocs tool can overwrite the content.
+		 * Put a dummy data item at the start to
+		 * avoid to generate NOBITS section.
+		 */
+		LONG(0);
+		FILL(0);
+		. += CONFIG_RELOCATION_TABLE_SIZE - 4;
+		__relocation_end = .;
+	}
+#endif
+
 	/*
 	 * struct alt_inst entries. From the header (alternative.h):
 	 * "Alternative instructions for different CPU types or capabilities"
-- 
2.19.1.6.gb485710b


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ