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]
Message-ID: <20240424155309.1719454-17-ardb+git@google.com>
Date: Wed, 24 Apr 2024 17:53:16 +0200
From: Ard Biesheuvel <ardb+git@...gle.com>
To: linux-kernel@...r.kernel.org
Cc: x86@...nel.org, Ard Biesheuvel <ardb@...nel.org>, Arnd Bergmann <arnd@...db.de>, 
	Eric Biederman <ebiederm@...ssion.com>, kexec@...ts.infradead.org, 
	Nathan Chancellor <nathan@...nel.org>, Nick Desaulniers <ndesaulniers@...gle.com>, 
	Kees Cook <keescook@...omium.org>, Bill Wendling <morbo@...gle.com>, 
	Justin Stitt <justinstitt@...gle.com>, Masahiro Yamada <masahiroy@...nel.org>
Subject: [RFC PATCH 6/9] kexec: Add support for fully linked purgatory executables

From: Ard Biesheuvel <ardb@...nel.org>

The purgatory ELF object is typically a partially linked object, which
puts the burden on the kexec loader to lay out the executable in memory,
and this involves (among other things) deciding the placement of the
sections in memory, and fixing up all relocations (relative and absolute
ones)

All of this can be greatly simplified by using a fully linked PIE ELF
executable instead, constructed in a way that removes the need for any
relocation processing or layout and allocation of individual sections.

By gathering all allocatable sections into a single PT_LOAD segment, and
relying on RIP-relative references, all relocations will be applied by
the linker, and the segment simply needs to be copied into memory.

So add a linker script and some minimal handling in generic code, which
can be used by architectures to opt into this approach. This will be
wired up for x86 in a subsequent patch.

Signed-off-by: Ard Biesheuvel <ardb@...nel.org>
---
 include/asm-generic/purgatory.lds | 34 ++++++++++
 kernel/kexec_file.c               | 68 +++++++++++++++++++-
 2 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/include/asm-generic/purgatory.lds b/include/asm-generic/purgatory.lds
new file mode 100644
index 000000000000..260c457f7608
--- /dev/null
+++ b/include/asm-generic/purgatory.lds
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+PHDRS
+{
+	text PT_LOAD FLAGS(7) FILEHDR PHDRS;
+}
+
+SECTIONS
+{
+	. = SIZEOF_HEADERS;
+
+	.text : {
+		*(.text .rodata* .kexec-purgatory .data*)
+	} :text
+
+	.bss : {
+		*(.bss .dynbss)
+	} :text
+
+	.rela.dyn : {
+		*(.rela.*)
+	}
+
+	.symtab 0 : { *(.symtab) }
+	.strtab 0 : { *(.strtab) }
+	.shstrtab 0 : { *(.shstrtab) }
+
+	/DISCARD/ : {
+		*(.interp .modinfo .dynsym .dynstr .hash .gnu.* .dynamic .comment)
+		*(.got .plt .got.plt .plt.got .note.* .eh_frame .sframe)
+	}
+}
+
+ASSERT(SIZEOF(.rela.dyn) == 0, "Absolute relocations detected");
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index bef2f6f2571b..6379f8dfc29f 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -1010,6 +1010,62 @@ static int kexec_apply_relocations(struct kimage *image)
 	return 0;
 }
 
+/*
+ * kexec_load_purgatory_pie - Load the position independent purgatory object.
+ * @pi:		Purgatory info struct.
+ * @kbuf:	Memory parameters to use.
+ *
+ * Load a purgatory PIE executable. This is a fully linked executable
+ * consisting of a single PT_LOAD segment that does not require any relocation
+ * processing.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+static int kexec_load_purgatory_pie(struct purgatory_info *pi,
+				    struct kexec_buf *kbuf)
+{
+	const Elf_Phdr *phdr = (void *)pi->ehdr + pi->ehdr->e_phoff;
+	int ret;
+
+	if (pi->ehdr->e_phnum != 1)
+		return -EINVAL;
+
+	kbuf->bufsz = phdr->p_filesz;
+	kbuf->memsz = phdr->p_memsz;
+	kbuf->buf_align = phdr->p_align;
+
+	kbuf->buffer = vzalloc(kbuf->bufsz);
+	if (!kbuf->buffer)
+		return -ENOMEM;
+
+	ret = kexec_add_buffer(kbuf);
+	if (ret)
+		goto out_free_kbuf;
+
+	kbuf->image->start = kbuf->mem + pi->ehdr->e_entry;
+
+	pi->sechdrs = vcalloc(pi->ehdr->e_shnum, pi->ehdr->e_shentsize);
+	if (!pi->sechdrs)
+		goto out_free_kbuf;
+
+	pi->purgatory_buf = memcpy(kbuf->buffer,
+				   (void *)pi->ehdr + phdr->p_offset,
+				   kbuf->bufsz);
+
+	memcpy(pi->sechdrs, (void *)pi->ehdr + pi->ehdr->e_shoff,
+	       pi->ehdr->e_shnum * pi->ehdr->e_shentsize);
+
+	for (int i = 0; i < pi->ehdr->e_shnum; i++)
+		if (pi->sechdrs[i].sh_flags & SHF_ALLOC)
+			pi->sechdrs[i].sh_addr += kbuf->mem;
+
+	return 0;
+
+out_free_kbuf:
+	vfree(kbuf->buffer);
+	return ret;
+}
+
 /*
  * kexec_load_purgatory - Load and relocate the purgatory object.
  * @image:	Image to add the purgatory to.
@@ -1031,6 +1087,9 @@ int kexec_load_purgatory(struct kimage *image, struct kexec_buf *kbuf)
 
 	pi->ehdr = (const Elf_Ehdr *)kexec_purgatory;
 
+	if (pi->ehdr->e_type != ET_REL)
+		return kexec_load_purgatory_pie(pi, kbuf);
+
 	ret = kexec_purgatory_setup_kbuf(pi, kbuf);
 	if (ret)
 		return ret;
@@ -1087,7 +1146,8 @@ static const Elf_Sym *kexec_purgatory_find_symbol(struct purgatory_info *pi,
 
 		/* Go through symbols for a match */
 		for (k = 0; k < sechdrs[i].sh_size/sizeof(Elf_Sym); k++) {
-			if (ELF_ST_BIND(syms[k].st_info) != STB_GLOBAL)
+			if (pi->ehdr->e_type == ET_REL &&
+			    ELF_ST_BIND(syms[k].st_info) != STB_GLOBAL)
 				continue;
 
 			if (strcmp(strtab + syms[k].st_name, name) != 0)
@@ -1159,6 +1219,12 @@ int kexec_purgatory_get_set_symbol(struct kimage *image, const char *name,
 
 	sym_buf = (char *)pi->purgatory_buf + sec->sh_offset + sym->st_value;
 
+	if (pi->ehdr->e_type != ET_REL) {
+		const Elf_Shdr *shdr = (void *)pi->ehdr + pi->ehdr->e_shoff;
+
+		sym_buf -= shdr[sym->st_shndx].sh_addr;
+	}
+
 	if (get_value)
 		memcpy((void *)buf, sym_buf, size);
 	else
-- 
2.44.0.769.g3c40516874-goog


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ