Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1718948 > unrolled thread
| Started by | AKASHI Takahiro <takahiro.akashi@linaro.org> |
|---|---|
| First post | 2017-08-24 10:20 +0200 |
| Last post | 2017-08-24 10:30 +0200 |
| Articles | 20 on this page of 37 — 5 participants |
Back to article view | Back to linux.kernel
[PATCH 00/14] arm64: kexec: add kexec_file_load support AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:20 +0200
[PATCH 14/14] arm64: kexec_file: add vmlinux format support AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:20 +0200
Re: [PATCH 14/14] arm64: kexec_file: add vmlinux format support Mark Rutland <mark.rutland@arm.com> - 2017-08-24 19:40 +0200
Re: [PATCH 14/14] arm64: kexec_file: add vmlinux format support AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-25 04:10 +0200
Re: [PATCH 14/14] arm64: kexec_file: add vmlinux format support Dave Young <dyoung@redhat.com> - 2017-08-25 08:20 +0200
[PATCH 08/14] arm64: kexec_file: create purgatory AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:20 +0200
Re: [PATCH 08/14] arm64: kexec_file: create purgatory Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2017-08-24 11:20 +0200
Re: [PATCH 08/14] arm64: kexec_file: create purgatory AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-25 03:20 +0200
Re: [PATCH 08/14] arm64: kexec_file: create purgatory Mark Rutland <mark.rutland@arm.com> - 2017-08-24 19:00 +0200
Re: [PATCH 08/14] arm64: kexec_file: create purgatory AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-25 03:10 +0200
Re: [PATCH 08/14] arm64: kexec_file: create purgatory Mark Rutland <mark.rutland@arm.com> - 2017-08-25 12:30 +0200
[PATCH 02/14] include: pe.h: remove message[] from mz header definition AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:20 +0200
Re: [PATCH 02/14] include: pe.h: remove message[] from mz header definition Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2017-08-24 11:10 +0200
[PATCH 01/14] MODSIGN: Export module signature definitions AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:20 +0200
[PATCH 09/14] arm64: kexec_file: add sha256 digest check in purgatory AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:30 +0200
Re: [PATCH 09/14] arm64: kexec_file: add sha256 digest check in purgatory Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2017-08-24 11:20 +0200
Re: [PATCH 09/14] arm64: kexec_file: add sha256 digest check in purgatory AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-25 03:30 +0200
Re: [PATCH 09/14] arm64: kexec_file: add sha256 digest check in purgatory Mark Rutland <mark.rutland@arm.com> - 2017-08-24 19:10 +0200
Re: [PATCH 09/14] arm64: kexec_file: add sha256 digest check in purgatory AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-25 03:30 +0200
Re: [PATCH 09/14] arm64: kexec_file: add sha256 digest check in purgatory Mark Rutland <mark.rutland@arm.com> - 2017-08-25 12:50 +0200
[PATCH 07/14] asm-generic: add kexec_file_load system call to unistd.h AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:30 +0200
Re: [PATCH 07/14] asm-generic: add kexec_file_load system call to unistd.h Arnd Bergmann <arnd@arndb.de> - 2017-08-24 13:00 +0200
[PATCH 13/14] arm64: kexec_file: add Image format support AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:30 +0200
Re: [PATCH 13/14] arm64: kexec_file: add Image format support Mark Rutland <mark.rutland@arm.com> - 2017-08-24 19:30 +0200
Re: [PATCH 13/14] arm64: kexec_file: add Image format support AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-25 04:00 +0200
[PATCH 03/14] resource: add walk_system_ram_res_rev() AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:30 +0200
Re: [PATCH 03/14] resource: add walk_system_ram_res_rev() Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2017-08-24 11:10 +0200
Re: [PATCH 03/14] resource: add walk_system_ram_res_rev() AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-25 03:00 +0200
[PATCH 10/14] arm64: kexec_file: load initrd, device-tree and purgatory segments AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:30 +0200
Re: [PATCH 10/14] arm64: kexec_file: load initrd, device-tree and purgatory segments Mark Rutland <mark.rutland@arm.com> - 2017-08-24 19:20 +0200
Re: [PATCH 10/14] arm64: kexec_file: load initrd, device-tree and purgatory segments AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-25 03:40 +0200
[PATCH 04/14] kexec_file: factor out vmlinux (elf) parser from powerpc AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:30 +0200
[PATCH 05/14] kexec_file: factor out crashdump elf header function from x86 AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:30 +0200
Re: [PATCH 05/14] kexec_file: factor out crashdump elf header function from x86 Dave Young <dyoung@redhat.com> - 2017-08-25 07:50 +0200
[PATCH 06/14] kexec_file: add kexec_add_segment() AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:30 +0200
[PATCH 12/14] arm64: enable KEXEC_FILE config AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:30 +0200
[PATCH 11/14] arm64: kexec_file: set up for crash dump adding elf core header AKASHI Takahiro <takahiro.akashi@linaro.org> - 2017-08-24 10:30 +0200
Page 1 of 2 [1] 2 Next page →
| From | AKASHI Takahiro <takahiro.akashi@linaro.org> |
|---|---|
| Date | 2017-08-24 10:20 +0200 |
| Subject | [PATCH 00/14] arm64: kexec: add kexec_file_load support |
| Message-ID | <uhVwR-3Wx-1@gated-at.bofh.it> |
This is the initial attempt of implementing kexec_file_load() support
on arm64.[1]
Most of the code is based on kexec-tools (along with some kernel code
from x86 and from powerpc, which also came from kexec-tools).
This patch series enables us to
* load the kernel, either Image or vmlinux, with kexec_file_load
system call, and
* optionally verify its signature at load time for trusted boot.
To load the kernel via kexec_file_load system call, a small change
needs to be applied on kexec-tools. See [2]. This enables '-s' option.
As we discussed a long time ago, users may not be allowed to specify
device-tree file of the 2nd kernel explicitly with kexec-tools, therefore
re-using the blob of the first kernel.
Regarding a method of placing the signature into the kernel binary,
* for 'Image', we conform with x86 (or rather Microsoft?) style of
signing since the binary can also be seen as in PE format
(assuming that CONFIG_EFI is enabled),
* for 'vmlinux', we follow powerpc approach[3]: The signature will
be appended just after the binary itself as module signing does.
This implies that we need to enable CONFIG_MODULE_SIG, too.
Powerpc is also going to support extended-file-attribute-based
verification[3], but arm64 doesn't for now partly because we don't
have TPM-based IMA at this moment.
Accordingly, we can use the existing commands, sbsign and sig-file
respectively, to sign the kernel. Please note that it is totally up to
the system what key/certificate is used for signing.
Some concerns(or future works):
* Even if the kernel is configured with CONFIG_RANDOMIZE_BASE, the 2nd
kernel won't be placed at a randomized address. We will have to
add some boot code similar to efi-stub to implement the feature.
* While big-endian kernel can support kernel signing, I'm not sure that
Image can be recognized as in PE format because x86 standard only
defines little-endian-based format.
So I tested big-endian kernel signing only with vmlinux.
* IMA(and file extended attribute)-based kexec
Patch #1 to #7 are all preparatory patches on generic side.
(Patch #1 is not part of mine, but a prerequisite from [4].)
Patch #8 and #9 are purgatory code.
Patch #10 to #12 are common for enabling kexec_file_load.
Patch #13 is for 'Image' support.
Patch #14 is for 'vmlinux' support.
[1] http://git.linaro.org/people/takahiro.akashi/linux-aarch64.git
branch:arm64/kexec_file
[2] http://git.linaro.org/people/takahiro.akashi/kexec-tools.git
branch:arm64/kexec_file
[3] http://lkml.iu.edu//hypermail/linux/kernel/1707.0/03669.html
[4] http://lkml.iu.edu//hypermail/linux/kernel/1707.0/03670.html
AKASHI Takahiro (13):
include: pe.h: remove message[] from mz header definition
resource: add walk_system_ram_res_rev()
kexec_file: factor out vmlinux (elf) parser from powerpc
kexec_file: factor out crashdump elf header function from x86
kexec_file: add kexec_add_segment()
asm-generic: add kexec_file_load system call to unistd.h
arm64: kexec_file: create purgatory
arm64: kexec_file: add sha256 digest check in purgatory
arm64: kexec_file: load initrd, device-tree and purgatory segments
arm64: kexec_file: set up for crash dump adding elf core header
arm64: enable KEXEC_FILE config
arm64: kexec_file: add Image format support
arm64: kexec_file: add vmlinux format support
Thiago Jung Bauermann (1):
MODSIGN: Export module signature definitions
arch/Kconfig | 3 +
arch/arm64/Kconfig | 33 ++
arch/arm64/Makefile | 1 +
arch/arm64/crypto/sha256-core.S_shipped | 2 +
arch/arm64/include/asm/kexec.h | 23 ++
arch/arm64/include/asm/kexec_file.h | 84 +++++
arch/arm64/kernel/Makefile | 5 +-
arch/arm64/kernel/kexec_elf.c | 216 ++++++++++++
arch/arm64/kernel/kexec_image.c | 112 ++++++
arch/arm64/kernel/machine_kexec_file.c | 606 ++++++++++++++++++++++++++++++++
arch/arm64/purgatory/Makefile | 43 +++
arch/arm64/purgatory/entry.S | 41 +++
arch/arm64/purgatory/purgatory.c | 20 ++
arch/arm64/purgatory/sha256-core.S | 1 +
arch/arm64/purgatory/sha256.c | 79 +++++
arch/arm64/purgatory/sha256.h | 1 +
arch/arm64/purgatory/string.c | 32 ++
arch/arm64/purgatory/string.h | 5 +
arch/powerpc/Kconfig | 1 +
arch/powerpc/kernel/kexec_elf_64.c | 464 ------------------------
arch/x86/kernel/crash.c | 324 -----------------
include/linux/elf.h | 62 ++++
include/linux/ioport.h | 3 +
include/linux/kexec.h | 39 ++
include/linux/module.h | 3 -
include/linux/module_signature.h | 47 +++
include/linux/pe.h | 2 +-
include/uapi/asm-generic/unistd.h | 4 +-
init/Kconfig | 6 +-
kernel/Makefile | 3 +-
kernel/crash_core.c | 333 ++++++++++++++++++
kernel/kexec_file.c | 47 +++
kernel/kexec_file_elf.c | 454 ++++++++++++++++++++++++
kernel/module.c | 1 +
kernel/module_signing.c | 74 ++--
kernel/resource.c | 48 +++
36 files changed, 2383 insertions(+), 839 deletions(-)
create mode 100644 arch/arm64/include/asm/kexec_file.h
create mode 100644 arch/arm64/kernel/kexec_elf.c
create mode 100644 arch/arm64/kernel/kexec_image.c
create mode 100644 arch/arm64/kernel/machine_kexec_file.c
create mode 100644 arch/arm64/purgatory/Makefile
create mode 100644 arch/arm64/purgatory/entry.S
create mode 100644 arch/arm64/purgatory/purgatory.c
create mode 100644 arch/arm64/purgatory/sha256-core.S
create mode 100644 arch/arm64/purgatory/sha256.c
create mode 100644 arch/arm64/purgatory/sha256.h
create mode 100644 arch/arm64/purgatory/string.c
create mode 100644 arch/arm64/purgatory/string.h
create mode 100644 include/linux/module_signature.h
create mode 100644 kernel/kexec_file_elf.c
--
2.14.1
[toc] | [next] | [standalone]
| From | AKASHI Takahiro <takahiro.akashi@linaro.org> |
|---|---|
| Date | 2017-08-24 10:20 +0200 |
| Subject | [PATCH 14/14] arm64: kexec_file: add vmlinux format support |
| Message-ID | <uhVwR-3Wx-3@gated-at.bofh.it> |
| In reply to | #1718948 |
The first PT_LOAD segment, which is assumed to be "text" code, in vmlinux
will be loaded at the offset of TEXT_OFFSET from the begining of system
memory. The other PT_LOAD segments are placed relative to the first one.
Regarding kernel verification, since there is no standard way to contain
a signature within elf binary, we follow PowerPC's (not yet upstreamed)
approach, that is, appending a signature right after the kernel binary
itself like module signing.
This way, the signature can be easily retrieved and verified with
verify_pkcs7_signature().
We can sign the kernel with sign-file command.
Unlike PowerPC, we don't support ima-based kexec for now since arm64
doesn't have any secure solution for system appraisal at this moment.
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/Kconfig | 8 ++
arch/arm64/include/asm/kexec_file.h | 1 +
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/kexec_elf.c | 216 +++++++++++++++++++++++++++++++++
arch/arm64/kernel/machine_kexec_file.c | 3 +
5 files changed, 229 insertions(+)
create mode 100644 arch/arm64/kernel/kexec_elf.c
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index c8f603700bdd..94021e66b826 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -772,11 +772,19 @@ config KEXEC_FILE_IMAGE_FMT
---help---
Select this option to enable 'Image' kernel loading.
+config KEXEC_FILE_ELF_FMT
+ bool "Enable vmlinux/elf support"
+ depends on KEXEC_FILE
+ select KEXEC_FILE_ELF
+ ---help---
+ Select this option to enable 'vmlinux' kernel loading.
+
config KEXEC_VERIFY_SIG
bool "Verify kernel signature during kexec_file_load() syscall"
depends on KEXEC_FILE
select SYSTEM_DATA_VERIFICATION
select SIGNED_PE_FILE_VERIFICATION if KEXEC_FILE_IMAGE_FMT
+ select MODULE_SIG_FORMAT if KEXEC_FILE_ELF_FMT
---help---
This option makes kernel signature verification mandatory for
the kexec_file_load() syscall.
diff --git a/arch/arm64/include/asm/kexec_file.h b/arch/arm64/include/asm/kexec_file.h
index 5df899aa0d2e..eaf2adc1121c 100644
--- a/arch/arm64/include/asm/kexec_file.h
+++ b/arch/arm64/include/asm/kexec_file.h
@@ -2,6 +2,7 @@
#define _ASM_KEXEC_FILE_H
extern struct kexec_file_ops kexec_image_ops;
+extern struct kexec_file_ops kexec_elf64_ops;
/**
* struct arm64_image_header - arm64 kernel image header.
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index a1161bab6810..1463337160ea 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -52,6 +52,7 @@ arm64-obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o relocate_kernel.o \
cpu-reset.o
arm64-obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o
arm64-obj-$(CONFIG_KEXEC_FILE_IMAGE_FMT) += kexec_image.o
+arm64-obj-$(CONFIG_KEXEC_FILE_ELF_FMT) += kexec_elf.o
arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o
arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
diff --git a/arch/arm64/kernel/kexec_elf.c b/arch/arm64/kernel/kexec_elf.c
new file mode 100644
index 000000000000..7bd3c1e1f65a
--- /dev/null
+++ b/arch/arm64/kernel/kexec_elf.c
@@ -0,0 +1,216 @@
+/*
+ * Kexec vmlinux loader
+
+ * Copyright (C) 2017 Linaro Limited
+ * Authors: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "kexec_file(elf): " fmt
+
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
+#include <linux/module_signature.h>
+#include <linux/types.h>
+#include <linux/verification.h>
+#include <asm/byteorder.h>
+#include <asm/kexec_file.h>
+#include <asm/memory.h>
+
+static int elf64_probe(const char *buf, unsigned long len)
+{
+ struct elfhdr ehdr;
+
+ /* Check for magic and architecture */
+ memcpy(&ehdr, buf, sizeof(ehdr));
+ if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) ||
+ (elf16_to_cpu(&ehdr, ehdr.e_machine) != EM_AARCH64))
+ return -ENOEXEC;
+
+ return 0;
+}
+
+static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr,
+ struct elf_info *elf_info,
+ unsigned long *kernel_load_addr)
+{
+ struct kexec_buf kbuf;
+ const struct elf_phdr *phdr;
+ const struct arm64_image_header *h;
+ unsigned long text_offset, rand_offset;
+ unsigned long page_offset, phys_offset;
+ int first_segment, i, ret = -ENOEXEC;
+
+ kbuf.image = image;
+ if (image->type == KEXEC_TYPE_CRASH) {
+ kbuf.buf_min = crashk_res.start;
+ kbuf.buf_max = crashk_res.end + 1;
+ } else {
+ kbuf.buf_min = 0;
+ kbuf.buf_max = ULONG_MAX;
+ }
+ kbuf.top_down = 0;
+
+ /* Load PT_LOAD segments. */
+ for (i = 0, first_segment = 1; i < ehdr->e_phnum; i++) {
+ phdr = &elf_info->proghdrs[i];
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
+ kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset;
+ kbuf.bufsz = min(phdr->p_filesz, phdr->p_memsz);
+ kbuf.memsz = phdr->p_memsz;
+ kbuf.buf_align = phdr->p_align;
+
+ if (first_segment) {
+ /*
+ * Identify TEXT_OFFSET:
+ * When CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET=y the image
+ * header could be offset in the elf segment. The linker
+ * script sets ehdr->e_entry to the start of text.
+ *
+ * NOTE: In v3.16 or older, h->text_offset is 0,
+ * so use the default, 0x80000
+ */
+ rand_offset = ehdr->e_entry - phdr->p_vaddr;
+ h = (struct arm64_image_header *)
+ (elf_info->buffer + phdr->p_offset +
+ rand_offset);
+
+ if (!arm64_header_check_magic(h))
+ goto out;
+
+ if (h->image_size)
+ text_offset = le64_to_cpu(h->text_offset);
+ else
+ text_offset = 0x80000;
+
+ /* Adjust kernel segment with TEXT_OFFSET */
+ kbuf.memsz += text_offset - rand_offset;
+
+ ret = kexec_add_buffer(&kbuf);
+ if (ret)
+ goto out;
+
+ image->segment[image->nr_segments - 1].mem
+ += text_offset - rand_offset;
+ image->segment[image->nr_segments - 1].memsz
+ -= text_offset - rand_offset;
+
+ *kernel_load_addr = kbuf.mem + text_offset;
+
+ /* for succeeding segmemts */
+ page_offset = ALIGN_DOWN(phdr->p_vaddr, SZ_2M);
+ phys_offset = kbuf.mem;
+
+ first_segment = 0;
+ } else {
+ /* Calculate physical address */
+ kbuf.mem = phdr->p_vaddr - page_offset + phys_offset;
+
+ ret = kexec_add_segment(&kbuf);
+ if (ret)
+ goto out;
+ }
+ }
+
+out:
+ return ret;
+}
+
+static void *elf64_load(struct kimage *image, char *kernel_buf,
+ unsigned long kernel_len, char *initrd,
+ unsigned long initrd_len, char *cmdline,
+ unsigned long cmdline_len)
+{
+ struct elfhdr ehdr;
+ struct elf_info elf_info;
+ unsigned long kernel_load_addr;
+ int ret;
+
+ /* Create elf core header segment */
+ ret = load_crashdump_segments(image);
+ if (ret)
+ goto out;
+
+ /* Load the kernel */
+ ret = build_elf_exec_info(kernel_buf, kernel_len, &ehdr, &elf_info);
+ if (ret)
+ goto out;
+
+ ret = elf_exec_load(image, &ehdr, &elf_info, &kernel_load_addr);
+ if (ret)
+ goto out;
+ pr_debug("Loaded the kernel at 0x%lx\n", kernel_load_addr);
+
+ /* Load additional data */
+ ret = load_other_segments(image, kernel_load_addr,
+ initrd, initrd_len, cmdline, cmdline_len);
+
+out:
+ elf_free_info(&elf_info);
+
+ return ERR_PTR(ret);
+}
+
+#ifdef CONFIG_KEXEC_VERIFY_SIG
+/*
+ * The file format is the exact same as module signing:
+ * <kernel> := <Image> + <signature part> + <marker>
+ * <signature part> := <signature data> + <struct module_signature>
+ */
+static int elf64_verify_sig(const char *kernel, unsigned long kernel_len)
+{
+ const size_t marker_len = sizeof(MODULE_SIG_STRING) - 1;
+ const struct module_signature *sig;
+ size_t file_len = kernel_len;
+ size_t sig_len;
+ const void *p;
+ int rc;
+
+ if (kernel_len <= marker_len + sizeof(*sig))
+ return -ENOENT;
+
+ /* Check for marker */
+ p = kernel + kernel_len - marker_len;
+ if (memcmp(p, MODULE_SIG_STRING, marker_len)) {
+ pr_err("probably the kernel is not signed.\n");
+ return -ENOENT;
+ }
+
+ /* Validate signature */
+ sig = (const struct module_signature *) (p - sizeof(*sig));
+ file_len -= marker_len;
+
+ rc = validate_module_sig(sig, kernel_len - marker_len);
+ if (rc) {
+ pr_err("signature is not valid\n");
+ return rc;
+ }
+
+ /* Verify kernel with signature */
+ sig_len = be32_to_cpu(sig->sig_len);
+ p -= sig_len + sizeof(*sig);
+ file_len -= sig_len + sizeof(*sig);
+
+ rc = verify_pkcs7_signature(kernel, p - (void *)kernel, p, sig_len,
+ NULL, VERIFYING_MODULE_SIGNATURE,
+ NULL, NULL);
+
+ return rc;
+}
+#endif
+
+struct kexec_file_ops kexec_elf64_ops = {
+ .probe = elf64_probe,
+ .load = elf64_load,
+#ifdef CONFIG_KEXEC_VERIFY_SIG
+ .verify_sig = elf64_verify_sig,
+#endif
+};
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index ab3b19d51727..cb1f24d98f87 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -31,6 +31,9 @@ static struct kexec_file_ops *kexec_file_loaders[] = {
#ifdef CONFIG_KEXEC_FILE_IMAGE_FMT
&kexec_image_ops,
#endif
+#ifdef CONFIG_KEXEC_FILE_ELF_FMT
+ &kexec_elf64_ops,
+#endif
};
int arch_kexec_kernel_image_probe(struct kimage *image, void *buf,
--
2.14.1
[toc] | [prev] | [next] | [standalone]
| From | Mark Rutland <mark.rutland@arm.com> |
|---|---|
| Date | 2017-08-24 19:40 +0200 |
| Subject | Re: [PATCH 14/14] arm64: kexec_file: add vmlinux format support |
| Message-ID | <ui4gO-17m-9@gated-at.bofh.it> |
| In reply to | #1718949 |
On Thu, Aug 24, 2017 at 05:18:11PM +0900, AKASHI Takahiro wrote:
> The first PT_LOAD segment, which is assumed to be "text" code, in vmlinux
> will be loaded at the offset of TEXT_OFFSET from the begining of system
> memory. The other PT_LOAD segments are placed relative to the first one.
I really don't like assuming things about the vmlinux ELF file.
> Regarding kernel verification, since there is no standard way to contain
> a signature within elf binary, we follow PowerPC's (not yet upstreamed)
> approach, that is, appending a signature right after the kernel binary
> itself like module signing.
I also *really* don't like this. It's a bizarre in-band mechanism,
without explcit information. It's not a nice ABI.
If we can load an Image, why do we need to be able to load a vmlinux?
[...]
> diff --git a/arch/arm64/kernel/kexec_elf.c b/arch/arm64/kernel/kexec_elf.c
> new file mode 100644
> index 000000000000..7bd3c1e1f65a
> --- /dev/null
> +++ b/arch/arm64/kernel/kexec_elf.c
> @@ -0,0 +1,216 @@
> +/*
> + * Kexec vmlinux loader
> +
> + * Copyright (C) 2017 Linaro Limited
> + * Authors: AKASHI Takahiro <takahiro.akashi@linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define pr_fmt(fmt) "kexec_file(elf): " fmt
> +
> +#include <linux/elf.h>
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/kexec.h>
> +#include <linux/module_signature.h>
> +#include <linux/types.h>
> +#include <linux/verification.h>
> +#include <asm/byteorder.h>
> +#include <asm/kexec_file.h>
> +#include <asm/memory.h>
> +
> +static int elf64_probe(const char *buf, unsigned long len)
> +{
> + struct elfhdr ehdr;
> +
> + /* Check for magic and architecture */
> + memcpy(&ehdr, buf, sizeof(ehdr));
> + if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) ||
> + (elf16_to_cpu(&ehdr, ehdr.e_machine) != EM_AARCH64))
> + return -ENOEXEC;
> +
> + return 0;
> +}
> +
> +static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr,
> + struct elf_info *elf_info,
> + unsigned long *kernel_load_addr)
> +{
> + struct kexec_buf kbuf;
> + const struct elf_phdr *phdr;
> + const struct arm64_image_header *h;
> + unsigned long text_offset, rand_offset;
> + unsigned long page_offset, phys_offset;
> + int first_segment, i, ret = -ENOEXEC;
> +
> + kbuf.image = image;
> + if (image->type == KEXEC_TYPE_CRASH) {
> + kbuf.buf_min = crashk_res.start;
> + kbuf.buf_max = crashk_res.end + 1;
> + } else {
> + kbuf.buf_min = 0;
> + kbuf.buf_max = ULONG_MAX;
> + }
> + kbuf.top_down = 0;
> +
> + /* Load PT_LOAD segments. */
> + for (i = 0, first_segment = 1; i < ehdr->e_phnum; i++) {
> + phdr = &elf_info->proghdrs[i];
> + if (phdr->p_type != PT_LOAD)
> + continue;
> +
> + kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset;
> + kbuf.bufsz = min(phdr->p_filesz, phdr->p_memsz);
> + kbuf.memsz = phdr->p_memsz;
> + kbuf.buf_align = phdr->p_align;
> +
> + if (first_segment) {
> + /*
> + * Identify TEXT_OFFSET:
> + * When CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET=y the image
> + * header could be offset in the elf segment. The linker
> + * script sets ehdr->e_entry to the start of text.
Please, let's not have to go delving into the vmlinux, knowing intimate
details about how it's put together.
> + *
> + * NOTE: In v3.16 or older, h->text_offset is 0,
> + * so use the default, 0x80000
> + */
> + rand_offset = ehdr->e_entry - phdr->p_vaddr;
> + h = (struct arm64_image_header *)
> + (elf_info->buffer + phdr->p_offset +
> + rand_offset);
> +
> + if (!arm64_header_check_magic(h))
> + goto out;
> +
> + if (h->image_size)
> + text_offset = le64_to_cpu(h->text_offset);
> + else
> + text_offset = 0x80000;
Surely we can share the Image header parsing with the Image parser?
The Image code had practically the exact same logic operating on the
header struct.
Thanks,
Mark.
[toc] | [prev] | [next] | [standalone]
| From | AKASHI Takahiro <takahiro.akashi@linaro.org> |
|---|---|
| Date | 2017-08-25 04:10 +0200 |
| Subject | Re: [PATCH 14/14] arm64: kexec_file: add vmlinux format support |
| Message-ID | <uicem-6mE-17@gated-at.bofh.it> |
| In reply to | #1719464 |
On Thu, Aug 24, 2017 at 06:30:50PM +0100, Mark Rutland wrote:
> On Thu, Aug 24, 2017 at 05:18:11PM +0900, AKASHI Takahiro wrote:
> > The first PT_LOAD segment, which is assumed to be "text" code, in vmlinux
> > will be loaded at the offset of TEXT_OFFSET from the begining of system
> > memory. The other PT_LOAD segments are placed relative to the first one.
>
> I really don't like assuming things about the vmlinux ELF file.
If so, vmlinux is not an appropriate format for loading.
> > Regarding kernel verification, since there is no standard way to contain
> > a signature within elf binary, we follow PowerPC's (not yet upstreamed)
> > approach, that is, appending a signature right after the kernel binary
> > itself like module signing.
>
> I also *really* don't like this. It's a bizarre in-band mechanism,
> without explcit information. It's not a nice ABI.
>
> If we can load an Image, why do we need to be able to load a vmlinux?
Well, kexec-tools does. I don't know why Geoff wanted to support vmlinux.
I'm just trying to support what kexec-tools does support.
> [...]
>
> > diff --git a/arch/arm64/kernel/kexec_elf.c b/arch/arm64/kernel/kexec_elf.c
> > new file mode 100644
> > index 000000000000..7bd3c1e1f65a
> > --- /dev/null
> > +++ b/arch/arm64/kernel/kexec_elf.c
> > @@ -0,0 +1,216 @@
> > +/*
> > + * Kexec vmlinux loader
> > +
> > + * Copyright (C) 2017 Linaro Limited
> > + * Authors: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + */
> > +
> > +#define pr_fmt(fmt) "kexec_file(elf): " fmt
> > +
> > +#include <linux/elf.h>
> > +#include <linux/err.h>
> > +#include <linux/errno.h>
> > +#include <linux/kernel.h>
> > +#include <linux/kexec.h>
> > +#include <linux/module_signature.h>
> > +#include <linux/types.h>
> > +#include <linux/verification.h>
> > +#include <asm/byteorder.h>
> > +#include <asm/kexec_file.h>
> > +#include <asm/memory.h>
> > +
> > +static int elf64_probe(const char *buf, unsigned long len)
> > +{
> > + struct elfhdr ehdr;
> > +
> > + /* Check for magic and architecture */
> > + memcpy(&ehdr, buf, sizeof(ehdr));
> > + if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) ||
> > + (elf16_to_cpu(&ehdr, ehdr.e_machine) != EM_AARCH64))
> > + return -ENOEXEC;
> > +
> > + return 0;
> > +}
> > +
> > +static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr,
> > + struct elf_info *elf_info,
> > + unsigned long *kernel_load_addr)
> > +{
> > + struct kexec_buf kbuf;
> > + const struct elf_phdr *phdr;
> > + const struct arm64_image_header *h;
> > + unsigned long text_offset, rand_offset;
> > + unsigned long page_offset, phys_offset;
> > + int first_segment, i, ret = -ENOEXEC;
> > +
> > + kbuf.image = image;
> > + if (image->type == KEXEC_TYPE_CRASH) {
> > + kbuf.buf_min = crashk_res.start;
> > + kbuf.buf_max = crashk_res.end + 1;
> > + } else {
> > + kbuf.buf_min = 0;
> > + kbuf.buf_max = ULONG_MAX;
> > + }
> > + kbuf.top_down = 0;
> > +
> > + /* Load PT_LOAD segments. */
> > + for (i = 0, first_segment = 1; i < ehdr->e_phnum; i++) {
> > + phdr = &elf_info->proghdrs[i];
> > + if (phdr->p_type != PT_LOAD)
> > + continue;
> > +
> > + kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset;
> > + kbuf.bufsz = min(phdr->p_filesz, phdr->p_memsz);
> > + kbuf.memsz = phdr->p_memsz;
> > + kbuf.buf_align = phdr->p_align;
> > +
> > + if (first_segment) {
> > + /*
> > + * Identify TEXT_OFFSET:
> > + * When CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET=y the image
> > + * header could be offset in the elf segment. The linker
> > + * script sets ehdr->e_entry to the start of text.
>
> Please, let's not have to go delving into the vmlinux, knowing intimate
> details about how it's put together.
If we don't need to take care of RANDOMIZE_TEXT_OFFSET, the code would
be much simpler and look similar to Image code.
>
> > + *
> > + * NOTE: In v3.16 or older, h->text_offset is 0,
> > + * so use the default, 0x80000
> > + */
> > + rand_offset = ehdr->e_entry - phdr->p_vaddr;
> > + h = (struct arm64_image_header *)
> > + (elf_info->buffer + phdr->p_offset +
> > + rand_offset);
> > +
> > + if (!arm64_header_check_magic(h))
> > + goto out;
> > +
> > + if (h->image_size)
> > + text_offset = le64_to_cpu(h->text_offset);
> > + else
> > + text_offset = 0x80000;
>
> Surely we can share the Image header parsing with the Image parser?
>
> The Image code had practically the exact same logic operating on the
> header struct.
Thanks,
-Takahiro AKASHI
> Thanks,
> Mark.
[toc] | [prev] | [next] | [standalone]
| From | Dave Young <dyoung@redhat.com> |
|---|---|
| Date | 2017-08-25 08:20 +0200 |
| Subject | Re: [PATCH 14/14] arm64: kexec_file: add vmlinux format support |
| Message-ID | <uig8h-r3-7@gated-at.bofh.it> |
| In reply to | #1719713 |
On 08/25/17 at 11:03am, AKASHI Takahiro wrote: > On Thu, Aug 24, 2017 at 06:30:50PM +0100, Mark Rutland wrote: > > On Thu, Aug 24, 2017 at 05:18:11PM +0900, AKASHI Takahiro wrote: > > > The first PT_LOAD segment, which is assumed to be "text" code, in vmlinux > > > will be loaded at the offset of TEXT_OFFSET from the begining of system > > > memory. The other PT_LOAD segments are placed relative to the first one. > > > > I really don't like assuming things about the vmlinux ELF file. > > If so, vmlinux is not an appropriate format for loading. > > > > Regarding kernel verification, since there is no standard way to contain > > > a signature within elf binary, we follow PowerPC's (not yet upstreamed) > > > approach, that is, appending a signature right after the kernel binary > > > itself like module signing. > > > > I also *really* don't like this. It's a bizarre in-band mechanism, > > without explcit information. It's not a nice ABI. > > > > If we can load an Image, why do we need to be able to load a vmlinux? > > Well, kexec-tools does. I don't know why Geoff wanted to support vmlinux. > I'm just trying to support what kexec-tools does support. We only add things when it is really necessary, kexec-tools functionalities should have some historic reasons. If only for doing kexec-tools has done I would say just not to do it. Thanks Dave
[toc] | [prev] | [next] | [standalone]
| From | AKASHI Takahiro <takahiro.akashi@linaro.org> |
|---|---|
| Date | 2017-08-24 10:20 +0200 |
| Subject | [PATCH 08/14] arm64: kexec_file: create purgatory |
| Message-ID | <uhVwR-3Wx-5@gated-at.bofh.it> |
| In reply to | #1718948 |
This is a basic purgtory, or a kind of glue code between the two kernel,
for arm64. We will later add a feature of verifying a digest check against
loaded memory segments.
arch_kexec_apply_relocations_add() is responsible for re-linking any
relative symbols in purgatory. Please note that the purgatory is not
an executable, but a non-linked archive of binaries so relative symbols
contained here must be resolved at kexec load time.
Despite that arm64_kernel_start and arm64_dtb_addr are only such global
variables now, arch_kexec_apply_relocations_add() can manage more various
types of relocations.
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/Makefile | 1 +
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/machine_kexec_file.c | 199 +++++++++++++++++++++++++++++++++
arch/arm64/purgatory/Makefile | 24 ++++
arch/arm64/purgatory/entry.S | 28 +++++
5 files changed, 253 insertions(+)
create mode 100644 arch/arm64/kernel/machine_kexec_file.c
create mode 100644 arch/arm64/purgatory/Makefile
create mode 100644 arch/arm64/purgatory/entry.S
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 9b41f1e3b1a0..429f60728c0a 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -105,6 +105,7 @@ core-$(CONFIG_XEN) += arch/arm64/xen/
core-$(CONFIG_CRYPTO) += arch/arm64/crypto/
libs-y := arch/arm64/lib/ $(libs-y)
core-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
+core-$(CONFIG_KEXEC_FILE) += arch/arm64/purgatory/
# Default target when executing plain make
boot := arch/arm64/boot
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index f2b4e816b6de..16e9f56b536a 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -50,6 +50,7 @@ arm64-obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
arm64-obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o
arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o \
cpu-reset.o
+arm64-obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o
arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o
arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
new file mode 100644
index 000000000000..183f7776d6dd
--- /dev/null
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -0,0 +1,199 @@
+/*
+ * kexec_file for arm64
+ *
+ * Copyright (C) 2017 Linaro Limited
+ * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ *
+ * Most code is derived from arm64 port of kexec-tools
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "kexec_file: " fmt
+
+#include <linux/elf.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+/*
+ * Apply purgatory relocations.
+ *
+ * ehdr: Pointer to elf headers
+ * sechdrs: Pointer to section headers.
+ * relsec: section index of SHT_RELA section.
+ *
+ * Note:
+ * Currently R_AARCH64_ABS64, R_AARCH64_LD_PREL_LO19 and R_AARCH64_CALL26
+ * are the only types to be generated from purgatory code.
+ * If we add more functionalities, other types may also be used.
+ */
+int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr,
+ Elf64_Shdr *sechdrs, unsigned int relsec)
+{
+ Elf64_Rela *rel;
+ Elf64_Shdr *section, *symtabsec;
+ Elf64_Sym *sym;
+ const char *strtab, *name, *shstrtab;
+ unsigned long address, sec_base, value;
+ void *location;
+ u64 *loc64;
+ u32 *loc32, imm;
+ unsigned int i;
+
+ /*
+ * ->sh_offset has been modified to keep the pointer to section
+ * contents in memory
+ */
+ rel = (void *)sechdrs[relsec].sh_offset;
+
+ /* Section to which relocations apply */
+ section = &sechdrs[sechdrs[relsec].sh_info];
+
+ pr_debug("reloc: Applying relocate section %u to %u\n", relsec,
+ sechdrs[relsec].sh_info);
+
+ /* Associated symbol table */
+ symtabsec = &sechdrs[sechdrs[relsec].sh_link];
+
+ /* String table */
+ if (symtabsec->sh_link >= ehdr->e_shnum) {
+ /* Invalid strtab section number */
+ pr_err("reloc: Invalid string table section index %d\n",
+ symtabsec->sh_link);
+ return -ENOEXEC;
+ }
+
+ strtab = (char *)sechdrs[symtabsec->sh_link].sh_offset;
+
+ /* section header string table */
+ shstrtab = (char *)sechdrs[ehdr->e_shstrndx].sh_offset;
+
+ for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+
+ /*
+ * rel[i].r_offset contains byte offset from beginning
+ * of section to the storage unit affected.
+ *
+ * This is location to update (->sh_offset). This is temporary
+ * buffer where section is currently loaded. This will finally
+ * be loaded to a different address later, pointed to by
+ * ->sh_addr. kexec takes care of moving it
+ * (kexec_load_segment()).
+ */
+ location = (void *)(section->sh_offset + rel[i].r_offset);
+
+ /* Final address of the location */
+ address = section->sh_addr + rel[i].r_offset;
+
+ /*
+ * rel[i].r_info contains information about symbol table index
+ * w.r.t which relocation must be made and type of relocation
+ * to apply. ELF64_R_SYM() and ELF64_R_TYPE() macros get
+ * these respectively.
+ */
+ sym = (Elf64_Sym *)symtabsec->sh_offset +
+ ELF64_R_SYM(rel[i].r_info);
+
+ if (sym->st_name)
+ name = strtab + sym->st_name;
+ else
+ name = shstrtab + sechdrs[sym->st_shndx].sh_name;
+
+ pr_debug("Symbol: %-16s info: %02x shndx: %02x value=%llx size: %llx reloc type:%d\n",
+ name, sym->st_info, sym->st_shndx, sym->st_value,
+ sym->st_size, (int)ELF64_R_TYPE(rel[i].r_info));
+
+ if (sym->st_shndx == SHN_UNDEF) {
+ pr_err("reloc: Undefined symbol: %s\n", name);
+ return -ENOEXEC;
+ }
+
+ if (sym->st_shndx == SHN_COMMON) {
+ pr_err("reloc: symbol '%s' in common section\n", name);
+ return -ENOEXEC;
+ }
+
+ if (sym->st_shndx == SHN_ABS) {
+ sec_base = 0;
+ } else if (sym->st_shndx < ehdr->e_shnum) {
+ sec_base = sechdrs[sym->st_shndx].sh_addr;
+ } else {
+ pr_err("reloc: Invalid section %d for symbol %s\n",
+ sym->st_shndx, name);
+ return -ENOEXEC;
+ }
+
+ value = sym->st_value;
+ value += sec_base;
+ value += rel[i].r_addend;
+
+ switch (ELF64_R_TYPE(rel[i].r_info)) {
+ case R_AARCH64_ABS64:
+ loc64 = location;
+ *loc64 = cpu_to_elf64(ehdr,
+ elf64_to_cpu(ehdr, *loc64) + value);
+ break;
+ case R_AARCH64_PREL32:
+ loc32 = location;
+ *loc32 = cpu_to_elf32(ehdr,
+ elf32_to_cpu(ehdr, *loc32) + value
+ - address);
+ break;
+ case R_AARCH64_LD_PREL_LO19:
+ loc32 = location;
+ *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
+ + (((value - address) << 3) & 0xffffe0));
+ break;
+ case R_AARCH64_ADR_PREL_LO21:
+ if (value & 3) {
+ pr_err("reloc: Unaligned value: %lx\n", value);
+ return -ENOEXEC;
+ }
+ loc32 = location;
+ *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
+ + (((value - address) << 3) & 0xffffe0));
+ break;
+ case R_AARCH64_ADR_PREL_PG_HI21:
+ imm = ((value & ~0xfff) - (address & ~0xfff)) >> 12;
+ loc32 = location;
+ *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
+ + ((imm & 3) << 29)
+ + ((imm & 0x1ffffc) << (5 - 2)));
+ break;
+ case R_AARCH64_ADD_ABS_LO12_NC:
+ loc32 = location;
+ *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
+ + ((value & 0xfff) << 10));
+ break;
+ case R_AARCH64_JUMP26:
+ loc32 = location;
+ *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
+ + (((value - address) >> 2) & 0x3ffffff));
+ break;
+ case R_AARCH64_CALL26:
+ loc32 = location;
+ *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
+ + (((value - address) >> 2) & 0x3ffffff));
+ break;
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ if (value & 7) {
+ pr_err("reloc: Unaligned value: %lx\n", value);
+ return -ENOEXEC;
+ }
+ loc32 = location;
+ *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
+ + ((value & 0xff8) << (10 - 3)));
+ break;
+ default:
+ pr_err("reloc: Unknown relocation type: %llu\n",
+ ELF64_R_TYPE(rel[i].r_info));
+ return -ENOEXEC;
+ }
+ }
+
+ return 0;
+}
diff --git a/arch/arm64/purgatory/Makefile b/arch/arm64/purgatory/Makefile
new file mode 100644
index 000000000000..c2127a2cbd51
--- /dev/null
+++ b/arch/arm64/purgatory/Makefile
@@ -0,0 +1,24 @@
+OBJECT_FILES_NON_STANDARD := y
+
+purgatory-y := entry.o
+
+targets += $(purgatory-y)
+PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y))
+
+LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined \
+ -nostdlib -z nodefaultlib
+targets += purgatory.ro
+
+$(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
+ $(call if_changed,ld)
+
+targets += kexec_purgatory.c
+
+CMD_BIN2C = $(objtree)/scripts/basic/bin2c
+quiet_cmd_bin2c = BIN2C $@
+ cmd_bin2c = $(CMD_BIN2C) kexec_purgatory < $< > $@
+
+$(obj)/kexec_purgatory.c: $(obj)/purgatory.ro FORCE
+ $(call if_changed,bin2c)
+
+obj-${CONFIG_KEXEC_FILE} += kexec_purgatory.o
diff --git a/arch/arm64/purgatory/entry.S b/arch/arm64/purgatory/entry.S
new file mode 100644
index 000000000000..bc4e6b3bf8a1
--- /dev/null
+++ b/arch/arm64/purgatory/entry.S
@@ -0,0 +1,28 @@
+/*
+ * kexec core purgatory
+ */
+#include <linux/linkage.h>
+
+.text
+
+ENTRY(purgatory_start)
+ /* Start new image. */
+ ldr x17, arm64_kernel_entry
+ ldr x0, arm64_dtb_addr
+ mov x1, xzr
+ mov x2, xzr
+ mov x3, xzr
+ br x17
+END(purgatory_start)
+
+.data
+
+.align 3
+
+ENTRY(arm64_kernel_entry)
+ .quad 0
+END(arm64_kernel_entry)
+
+ENTRY(arm64_dtb_addr)
+ .quad 0
+END(arm64_dtb_addr)
--
2.14.1
[toc] | [prev] | [next] | [standalone]
| From | Ard Biesheuvel <ard.biesheuvel@linaro.org> |
|---|---|
| Date | 2017-08-24 11:20 +0200 |
| Subject | Re: [PATCH 08/14] arm64: kexec_file: create purgatory |
| Message-ID | <uhWsV-4xQ-15@gated-at.bofh.it> |
| In reply to | #1718951 |
On 24 August 2017 at 09:18, AKASHI Takahiro <takahiro.akashi@linaro.org> wrote:
> This is a basic purgtory, or a kind of glue code between the two kernel,
> for arm64. We will later add a feature of verifying a digest check against
> loaded memory segments.
>
> arch_kexec_apply_relocations_add() is responsible for re-linking any
> relative symbols in purgatory. Please note that the purgatory is not
> an executable, but a non-linked archive of binaries so relative symbols
> contained here must be resolved at kexec load time.
This sounds fragile to me. What is the reason we cannot let the linker
deal with this, similar to, e.g., how the VDSO gets linked?
Otherwise, couldn't we reuse the module loader to get these objects
relocated in memory? I'm sure there are differences that would require
some changes there, but implementing all of this again sounds like
overkill to me.
> Despite that arm64_kernel_start and arm64_dtb_addr are only such global
> variables now, arch_kexec_apply_relocations_add() can manage more various
> types of relocations.
>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> ---
> arch/arm64/Makefile | 1 +
> arch/arm64/kernel/Makefile | 1 +
> arch/arm64/kernel/machine_kexec_file.c | 199 +++++++++++++++++++++++++++++++++
> arch/arm64/purgatory/Makefile | 24 ++++
> arch/arm64/purgatory/entry.S | 28 +++++
> 5 files changed, 253 insertions(+)
> create mode 100644 arch/arm64/kernel/machine_kexec_file.c
> create mode 100644 arch/arm64/purgatory/Makefile
> create mode 100644 arch/arm64/purgatory/entry.S
>
> diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
> index 9b41f1e3b1a0..429f60728c0a 100644
> --- a/arch/arm64/Makefile
> +++ b/arch/arm64/Makefile
> @@ -105,6 +105,7 @@ core-$(CONFIG_XEN) += arch/arm64/xen/
> core-$(CONFIG_CRYPTO) += arch/arm64/crypto/
> libs-y := arch/arm64/lib/ $(libs-y)
> core-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
> +core-$(CONFIG_KEXEC_FILE) += arch/arm64/purgatory/
>
> # Default target when executing plain make
> boot := arch/arm64/boot
> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> index f2b4e816b6de..16e9f56b536a 100644
> --- a/arch/arm64/kernel/Makefile
> +++ b/arch/arm64/kernel/Makefile
> @@ -50,6 +50,7 @@ arm64-obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
> arm64-obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o
> arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o \
> cpu-reset.o
> +arm64-obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o
> arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o
> arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
> arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
> diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
> new file mode 100644
> index 000000000000..183f7776d6dd
> --- /dev/null
> +++ b/arch/arm64/kernel/machine_kexec_file.c
> @@ -0,0 +1,199 @@
> +/*
> + * kexec_file for arm64
> + *
> + * Copyright (C) 2017 Linaro Limited
> + * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> + *
> + * Most code is derived from arm64 port of kexec-tools
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define pr_fmt(fmt) "kexec_file: " fmt
> +
> +#include <linux/elf.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <asm/byteorder.h>
> +
> +/*
> + * Apply purgatory relocations.
> + *
> + * ehdr: Pointer to elf headers
> + * sechdrs: Pointer to section headers.
> + * relsec: section index of SHT_RELA section.
> + *
> + * Note:
> + * Currently R_AARCH64_ABS64, R_AARCH64_LD_PREL_LO19 and R_AARCH64_CALL26
> + * are the only types to be generated from purgatory code.
> + * If we add more functionalities, other types may also be used.
> + */
> +int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr,
> + Elf64_Shdr *sechdrs, unsigned int relsec)
> +{
> + Elf64_Rela *rel;
> + Elf64_Shdr *section, *symtabsec;
> + Elf64_Sym *sym;
> + const char *strtab, *name, *shstrtab;
> + unsigned long address, sec_base, value;
> + void *location;
> + u64 *loc64;
> + u32 *loc32, imm;
> + unsigned int i;
> +
> + /*
> + * ->sh_offset has been modified to keep the pointer to section
> + * contents in memory
> + */
> + rel = (void *)sechdrs[relsec].sh_offset;
> +
> + /* Section to which relocations apply */
> + section = &sechdrs[sechdrs[relsec].sh_info];
> +
> + pr_debug("reloc: Applying relocate section %u to %u\n", relsec,
> + sechdrs[relsec].sh_info);
> +
> + /* Associated symbol table */
> + symtabsec = &sechdrs[sechdrs[relsec].sh_link];
> +
> + /* String table */
> + if (symtabsec->sh_link >= ehdr->e_shnum) {
> + /* Invalid strtab section number */
> + pr_err("reloc: Invalid string table section index %d\n",
> + symtabsec->sh_link);
> + return -ENOEXEC;
> + }
> +
> + strtab = (char *)sechdrs[symtabsec->sh_link].sh_offset;
> +
> + /* section header string table */
> + shstrtab = (char *)sechdrs[ehdr->e_shstrndx].sh_offset;
> +
> + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
> +
> + /*
> + * rel[i].r_offset contains byte offset from beginning
> + * of section to the storage unit affected.
> + *
> + * This is location to update (->sh_offset). This is temporary
> + * buffer where section is currently loaded. This will finally
> + * be loaded to a different address later, pointed to by
> + * ->sh_addr. kexec takes care of moving it
> + * (kexec_load_segment()).
> + */
> + location = (void *)(section->sh_offset + rel[i].r_offset);
> +
> + /* Final address of the location */
> + address = section->sh_addr + rel[i].r_offset;
> +
> + /*
> + * rel[i].r_info contains information about symbol table index
> + * w.r.t which relocation must be made and type of relocation
> + * to apply. ELF64_R_SYM() and ELF64_R_TYPE() macros get
> + * these respectively.
> + */
> + sym = (Elf64_Sym *)symtabsec->sh_offset +
> + ELF64_R_SYM(rel[i].r_info);
> +
> + if (sym->st_name)
> + name = strtab + sym->st_name;
> + else
> + name = shstrtab + sechdrs[sym->st_shndx].sh_name;
> +
> + pr_debug("Symbol: %-16s info: %02x shndx: %02x value=%llx size: %llx reloc type:%d\n",
> + name, sym->st_info, sym->st_shndx, sym->st_value,
> + sym->st_size, (int)ELF64_R_TYPE(rel[i].r_info));
> +
> + if (sym->st_shndx == SHN_UNDEF) {
> + pr_err("reloc: Undefined symbol: %s\n", name);
> + return -ENOEXEC;
> + }
> +
> + if (sym->st_shndx == SHN_COMMON) {
> + pr_err("reloc: symbol '%s' in common section\n", name);
> + return -ENOEXEC;
> + }
> +
> + if (sym->st_shndx == SHN_ABS) {
> + sec_base = 0;
> + } else if (sym->st_shndx < ehdr->e_shnum) {
> + sec_base = sechdrs[sym->st_shndx].sh_addr;
> + } else {
> + pr_err("reloc: Invalid section %d for symbol %s\n",
> + sym->st_shndx, name);
> + return -ENOEXEC;
> + }
> +
> + value = sym->st_value;
> + value += sec_base;
> + value += rel[i].r_addend;
> +
> + switch (ELF64_R_TYPE(rel[i].r_info)) {
> + case R_AARCH64_ABS64:
> + loc64 = location;
> + *loc64 = cpu_to_elf64(ehdr,
> + elf64_to_cpu(ehdr, *loc64) + value);
> + break;
> + case R_AARCH64_PREL32:
> + loc32 = location;
> + *loc32 = cpu_to_elf32(ehdr,
> + elf32_to_cpu(ehdr, *loc32) + value
> + - address);
> + break;
> + case R_AARCH64_LD_PREL_LO19:
> + loc32 = location;
> + *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
> + + (((value - address) << 3) & 0xffffe0));
> + break;
> + case R_AARCH64_ADR_PREL_LO21:
> + if (value & 3) {
> + pr_err("reloc: Unaligned value: %lx\n", value);
> + return -ENOEXEC;
> + }
> + loc32 = location;
> + *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
> + + (((value - address) << 3) & 0xffffe0));
> + break;
> + case R_AARCH64_ADR_PREL_PG_HI21:
> + imm = ((value & ~0xfff) - (address & ~0xfff)) >> 12;
> + loc32 = location;
> + *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
> + + ((imm & 3) << 29)
> + + ((imm & 0x1ffffc) << (5 - 2)));
> + break;
> + case R_AARCH64_ADD_ABS_LO12_NC:
> + loc32 = location;
> + *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
> + + ((value & 0xfff) << 10));
> + break;
> + case R_AARCH64_JUMP26:
> + loc32 = location;
> + *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
> + + (((value - address) >> 2) & 0x3ffffff));
> + break;
> + case R_AARCH64_CALL26:
> + loc32 = location;
> + *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
> + + (((value - address) >> 2) & 0x3ffffff));
> + break;
> + case R_AARCH64_LDST64_ABS_LO12_NC:
> + if (value & 7) {
> + pr_err("reloc: Unaligned value: %lx\n", value);
> + return -ENOEXEC;
> + }
> + loc32 = location;
> + *loc32 = cpu_to_le32(le32_to_cpu(*loc32)
> + + ((value & 0xff8) << (10 - 3)));
> + break;
> + default:
> + pr_err("reloc: Unknown relocation type: %llu\n",
> + ELF64_R_TYPE(rel[i].r_info));
> + return -ENOEXEC;
> + }
> + }
> +
> + return 0;
> +}
> diff --git a/arch/arm64/purgatory/Makefile b/arch/arm64/purgatory/Makefile
> new file mode 100644
> index 000000000000..c2127a2cbd51
> --- /dev/null
> +++ b/arch/arm64/purgatory/Makefile
> @@ -0,0 +1,24 @@
> +OBJECT_FILES_NON_STANDARD := y
> +
> +purgatory-y := entry.o
> +
> +targets += $(purgatory-y)
> +PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y))
> +
> +LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined \
> + -nostdlib -z nodefaultlib
> +targets += purgatory.ro
> +
> +$(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
> + $(call if_changed,ld)
> +
> +targets += kexec_purgatory.c
> +
> +CMD_BIN2C = $(objtree)/scripts/basic/bin2c
> +quiet_cmd_bin2c = BIN2C $@
> + cmd_bin2c = $(CMD_BIN2C) kexec_purgatory < $< > $@
> +
> +$(obj)/kexec_purgatory.c: $(obj)/purgatory.ro FORCE
> + $(call if_changed,bin2c)
> +
> +obj-${CONFIG_KEXEC_FILE} += kexec_purgatory.o
> diff --git a/arch/arm64/purgatory/entry.S b/arch/arm64/purgatory/entry.S
> new file mode 100644
> index 000000000000..bc4e6b3bf8a1
> --- /dev/null
> +++ b/arch/arm64/purgatory/entry.S
> @@ -0,0 +1,28 @@
> +/*
> + * kexec core purgatory
> + */
> +#include <linux/linkage.h>
> +
> +.text
> +
> +ENTRY(purgatory_start)
> + /* Start new image. */
> + ldr x17, arm64_kernel_entry
> + ldr x0, arm64_dtb_addr
> + mov x1, xzr
> + mov x2, xzr
> + mov x3, xzr
> + br x17
> +END(purgatory_start)
> +
> +.data
> +
> +.align 3
> +
> +ENTRY(arm64_kernel_entry)
> + .quad 0
> +END(arm64_kernel_entry)
> +
> +ENTRY(arm64_dtb_addr)
> + .quad 0
> +END(arm64_dtb_addr)
> --
> 2.14.1
>
[toc] | [prev] | [next] | [standalone]
| From | AKASHI Takahiro <takahiro.akashi@linaro.org> |
|---|---|
| Date | 2017-08-25 03:20 +0200 |
| Subject | Re: [PATCH 08/14] arm64: kexec_file: create purgatory |
| Message-ID | <uibrY-5Rl-5@gated-at.bofh.it> |
| In reply to | #1719049 |
On Thu, Aug 24, 2017 at 10:10:37AM +0100, Ard Biesheuvel wrote: > On 24 August 2017 at 09:18, AKASHI Takahiro <takahiro.akashi@linaro.org> wrote: > > This is a basic purgtory, or a kind of glue code between the two kernel, > > for arm64. We will later add a feature of verifying a digest check against > > loaded memory segments. > > > > arch_kexec_apply_relocations_add() is responsible for re-linking any > > relative symbols in purgatory. Please note that the purgatory is not > > an executable, but a non-linked archive of binaries so relative symbols > > contained here must be resolved at kexec load time. > > This sounds fragile to me. What is the reason we cannot let the linker > deal with this, similar to, e.g., how the VDSO gets linked? Please note this is exactly what x86 code does. I guess that the reason is that x86 guys borrowed the logic directly from kexec-tools. > Otherwise, couldn't we reuse the module loader to get these objects > relocated in memory? I'm sure there are differences that would require > some changes there, but implementing all of this again sounds like > overkill to me. I'll look at both of your suggestions. Thanks, -Takahiro AKASHI
[toc] | [prev] | [next] | [standalone]
| From | Mark Rutland <mark.rutland@arm.com> |
|---|---|
| Date | 2017-08-24 19:00 +0200 |
| Subject | Re: [PATCH 08/14] arm64: kexec_file: create purgatory |
| Message-ID | <ui3E5-Db-13@gated-at.bofh.it> |
| In reply to | #1718951 |
On Thu, Aug 24, 2017 at 05:18:05PM +0900, AKASHI Takahiro wrote: > This is a basic purgtory, or a kind of glue code between the two kernel, > for arm64. We will later add a feature of verifying a digest check against > loaded memory segments. > > arch_kexec_apply_relocations_add() is responsible for re-linking any > relative symbols in purgatory. Please note that the purgatory is not > an executable, but a non-linked archive of binaries so relative symbols > contained here must be resolved at kexec load time. > Despite that arm64_kernel_start and arm64_dtb_addr are only such global > variables now, arch_kexec_apply_relocations_add() can manage more various > types of relocations. Why does the purgatory code need to be so complex? Why is it not possible to write this as position-independent asm? > +/* > + * Apply purgatory relocations. > + * > + * ehdr: Pointer to elf headers > + * sechdrs: Pointer to section headers. > + * relsec: section index of SHT_RELA section. > + * > + * Note: > + * Currently R_AARCH64_ABS64, R_AARCH64_LD_PREL_LO19 and R_AARCH64_CALL26 > + * are the only types to be generated from purgatory code. Is this all that has been observed, or is this ensured somehow? The arch_kexec_apply_relocations_add() function below duplicates a lot of logic that already exists in the arm64 module loader's apply_relocate_add() function. Please reuse that code. Having a duplicate or alternative implementation is just asking for subtle bugs. Thanks, Mark.
[toc] | [prev] | [next] | [standalone]
| From | AKASHI Takahiro <takahiro.akashi@linaro.org> |
|---|---|
| Date | 2017-08-25 03:10 +0200 |
| Subject | Re: [PATCH 08/14] arm64: kexec_file: create purgatory |
| Message-ID | <uibih-5Ll-1@gated-at.bofh.it> |
| In reply to | #1719435 |
On Thu, Aug 24, 2017 at 05:56:17PM +0100, Mark Rutland wrote: > On Thu, Aug 24, 2017 at 05:18:05PM +0900, AKASHI Takahiro wrote: > > This is a basic purgtory, or a kind of glue code between the two kernel, > > for arm64. We will later add a feature of verifying a digest check against > > loaded memory segments. > > > > arch_kexec_apply_relocations_add() is responsible for re-linking any > > relative symbols in purgatory. Please note that the purgatory is not > > an executable, but a non-linked archive of binaries so relative symbols > > contained here must be resolved at kexec load time. > > Despite that arm64_kernel_start and arm64_dtb_addr are only such global > > variables now, arch_kexec_apply_relocations_add() can manage more various > > types of relocations. > > Why does the purgatory code need to be so complex? > > Why is it not possible to write this as position-independent asm? I don't get your point, but please note that these values are also re-written by the 1st kernel when it loads the 2nd kernel and so they must appear as globals. > > +/* > > + * Apply purgatory relocations. > > + * > > + * ehdr: Pointer to elf headers > > + * sechdrs: Pointer to section headers. > > + * relsec: section index of SHT_RELA section. > > + * > > + * Note: > > + * Currently R_AARCH64_ABS64, R_AARCH64_LD_PREL_LO19 and R_AARCH64_CALL26 > > + * are the only types to be generated from purgatory code. > > Is this all that has been observed, or is this ensured somehow? It was observed by inserting a debug print message in this function, I'm not sure whether we can restrict only those three types. > The arch_kexec_apply_relocations_add() function below duplicates a lot > of logic that already exists in the arm64 module loader's > apply_relocate_add() function. > > Please reuse that code. Having a duplicate or alternative implementation > is just asking for subtle bugs. Okey, I'll look at it. Thanks, -Takahiro AKASHI > Thanks, > Mark.
[toc] | [prev] | [next] | [standalone]
| From | Mark Rutland <mark.rutland@arm.com> |
|---|---|
| Date | 2017-08-25 12:30 +0200 |
| Subject | Re: [PATCH 08/14] arm64: kexec_file: create purgatory |
| Message-ID | <uik2f-2OI-35@gated-at.bofh.it> |
| In reply to | #1719692 |
On Fri, Aug 25, 2017 at 10:00:59AM +0900, AKASHI Takahiro wrote: > On Thu, Aug 24, 2017 at 05:56:17PM +0100, Mark Rutland wrote: > > On Thu, Aug 24, 2017 at 05:18:05PM +0900, AKASHI Takahiro wrote: > > > This is a basic purgtory, or a kind of glue code between the two kernel, > > > for arm64. We will later add a feature of verifying a digest check against > > > loaded memory segments. > > > > > > arch_kexec_apply_relocations_add() is responsible for re-linking any > > > relative symbols in purgatory. Please note that the purgatory is not > > > an executable, but a non-linked archive of binaries so relative symbols > > > contained here must be resolved at kexec load time. > > > Despite that arm64_kernel_start and arm64_dtb_addr are only such global > > > variables now, arch_kexec_apply_relocations_add() can manage more various > > > types of relocations. > > > > Why does the purgatory code need to be so complex? > > > > Why is it not possible to write this as position-independent asm? > > I don't get your point, but please note that these values are also > re-written by the 1st kernel when it loads the 2nd kernel and so > they must appear as globals. My fear about complexity is that we must "re-link" the purgatory. I don't understand why that has to be necessary. Surely we can have the purgatory code be position independent, and store those globals in a single struct purgatory_info that we can fill in from the host? i.e. similar to what we do for values shared with the VDSO, where we just poke vdso_data->field, no re-linking required. Otherwise, why can't the purgatory code be written in assembly? AFAICT, the only complex part is the hashing code, which I don't beleive is strictly necessary. [...] > > > +/* > > > + * Apply purgatory relocations. > > > + * > > > + * ehdr: Pointer to elf headers > > > + * sechdrs: Pointer to section headers. > > > + * relsec: section index of SHT_RELA section. > > > + * > > > + * Note: > > > + * Currently R_AARCH64_ABS64, R_AARCH64_LD_PREL_LO19 and R_AARCH64_CALL26 > > > + * are the only types to be generated from purgatory code. > > > > Is this all that has been observed, or is this ensured somehow? > > It was observed by inserting a debug print message in this function, > I'm not sure whether we can restrict only those three types. If we have to perform linking, I don't think we can assume the above is sufficient. > > The arch_kexec_apply_relocations_add() function below duplicates a lot > > of logic that already exists in the arm64 module loader's > > apply_relocate_add() function. > > > > Please reuse that code. Having a duplicate or alternative implementation > > is just asking for subtle bugs. > > Okey, I'll look at it. Ok. As above, I think it would be preferable that we avoid linking entirely. Thanks, Mark.
[toc] | [prev] | [next] | [standalone]
| From | AKASHI Takahiro <takahiro.akashi@linaro.org> |
|---|---|
| Date | 2017-08-24 10:20 +0200 |
| Subject | [PATCH 02/14] include: pe.h: remove message[] from mz header definition |
| Message-ID | <uhVwR-3Wx-15@gated-at.bofh.it> |
| In reply to | #1718948 |
message[] field won't be part of the definition of mz header.
This change is crucial for enabling kexec_file_load on arm64 because
arm64's "Image" binary, as in PE format, doesn't have any data for it and
accordingly the following check in pefile_parse_binary() will fail:
chkaddr(cursor, mz->peaddr, sizeof(*pe));
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: David Howells <dhowells@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: David S. Miller <davem@davemloft.net>
---
include/linux/pe.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/pe.h b/include/linux/pe.h
index 143ce75be5f0..3482b18a48b5 100644
--- a/include/linux/pe.h
+++ b/include/linux/pe.h
@@ -166,7 +166,7 @@ struct mz_hdr {
uint16_t oem_info; /* oem specific */
uint16_t reserved1[10]; /* reserved */
uint32_t peaddr; /* address of pe header */
- char message[64]; /* message to print */
+ char message[]; /* message to print */
};
struct mz_reloc {
--
2.14.1
[toc] | [prev] | [next] | [standalone]
| From | Ard Biesheuvel <ard.biesheuvel@linaro.org> |
|---|---|
| Date | 2017-08-24 11:10 +0200 |
| Subject | Re: [PATCH 02/14] include: pe.h: remove message[] from mz header definition |
| Message-ID | <uhWjf-4uA-1@gated-at.bofh.it> |
| In reply to | #1718954 |
On 24 August 2017 at 09:17, AKASHI Takahiro <takahiro.akashi@linaro.org> wrote:
> message[] field won't be part of the definition of mz header.
>
> This change is crucial for enabling kexec_file_load on arm64 because
> arm64's "Image" binary, as in PE format, doesn't have any data for it and
> accordingly the following check in pefile_parse_binary() will fail:
>
> chkaddr(cursor, mz->peaddr, sizeof(*pe));
>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Cc: David Howells <dhowells@redhat.com>
> Cc: Vivek Goyal <vgoyal@redhat.com>
> Cc: Herbert Xu <herbert@gondor.apana.org.au>
> Cc: David S. Miller <davem@davemloft.net>
> ---
> include/linux/pe.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/include/linux/pe.h b/include/linux/pe.h
> index 143ce75be5f0..3482b18a48b5 100644
> --- a/include/linux/pe.h
> +++ b/include/linux/pe.h
> @@ -166,7 +166,7 @@ struct mz_hdr {
> uint16_t oem_info; /* oem specific */
> uint16_t reserved1[10]; /* reserved */
> uint32_t peaddr; /* address of pe header */
> - char message[64]; /* message to print */
> + char message[]; /* message to print */
> };
>
> struct mz_reloc {
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
[toc] | [prev] | [next] | [standalone]
| From | AKASHI Takahiro <takahiro.akashi@linaro.org> |
|---|---|
| Date | 2017-08-24 10:20 +0200 |
| Subject | [PATCH 01/14] MODSIGN: Export module signature definitions |
| Message-ID | <uhVwS-3Wx-31@gated-at.bofh.it> |
| In reply to | #1718948 |
From: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
IMA will use the module_signature format for append signatures, so export
the relevant definitions and factor out the code which verifies that the
appended signature trailer is valid.
Also, create a CONFIG_MODULE_SIG_FORMAT option so that IMA can select it
and be able to use validate_module_signature without having to depend on
CONFIG_MODULE_SIG.
Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
include/linux/module.h | 3 --
include/linux/module_signature.h | 47 +++++++++++++++++++++++++
init/Kconfig | 6 +++-
kernel/Makefile | 2 +-
kernel/module.c | 1 +
kernel/module_signing.c | 74 +++++++++++++++++-----------------------
6 files changed, 85 insertions(+), 48 deletions(-)
create mode 100644 include/linux/module_signature.h
diff --git a/include/linux/module.h b/include/linux/module.h
index e7bdd549e527..672ad2016262 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -23,9 +23,6 @@
#include <linux/percpu.h>
#include <asm/module.h>
-/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
-#define MODULE_SIG_STRING "~Module signature appended~\n"
-
/* Not Yet Implemented */
#define MODULE_SUPPORTED_DEVICE(name)
diff --git a/include/linux/module_signature.h b/include/linux/module_signature.h
new file mode 100644
index 000000000000..e80728e5b86c
--- /dev/null
+++ b/include/linux/module_signature.h
@@ -0,0 +1,47 @@
+/* Module signature handling.
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_MODULE_SIGNATURE_H
+#define _LINUX_MODULE_SIGNATURE_H
+
+/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
+#define MODULE_SIG_STRING "~Module signature appended~\n"
+
+enum pkey_id_type {
+ PKEY_ID_PGP, /* OpenPGP generated key ID */
+ PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */
+ PKEY_ID_PKCS7, /* Signature in PKCS#7 message */
+};
+
+/*
+ * Module signature information block.
+ *
+ * The constituents of the signature section are, in order:
+ *
+ * - Signer's name
+ * - Key identifier
+ * - Signature data
+ * - Information block
+ */
+struct module_signature {
+ u8 algo; /* Public-key crypto algorithm [0] */
+ u8 hash; /* Digest algorithm [0] */
+ u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */
+ u8 signer_len; /* Length of signer's name [0] */
+ u8 key_id_len; /* Length of key identifier [0] */
+ u8 __pad[3];
+ __be32 sig_len; /* Length of signature data */
+};
+
+int validate_module_sig(const struct module_signature *ms, size_t file_len);
+int mod_verify_sig(const void *mod, unsigned long *_modlen);
+
+#endif /* _LINUX_MODULE_SIGNATURE_H */
diff --git a/init/Kconfig b/init/Kconfig
index 8514b25db21c..c3ac1170b93a 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1734,7 +1734,7 @@ config MODULE_SRCVERSION_ALL
config MODULE_SIG
bool "Module signature verification"
depends on MODULES
- select SYSTEM_DATA_VERIFICATION
+ select MODULE_SIG_FORMAT
help
Check modules for valid signatures upon load: the signature
is simply appended to the module. For more information see
@@ -1749,6 +1749,10 @@ config MODULE_SIG
debuginfo strip done by some packagers (such as rpmbuild) and
inclusion into an initramfs that wants the module size reduced.
+config MODULE_SIG_FORMAT
+ def_bool n
+ select SYSTEM_DATA_VERIFICATION
+
config MODULE_SIG_FORCE
bool "Require modules to be validly signed"
depends on MODULE_SIG
diff --git a/kernel/Makefile b/kernel/Makefile
index 4cb8e8b23c6e..d5f9748ab19f 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -56,7 +56,7 @@ obj-y += up.o
endif
obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += module.o
-obj-$(CONFIG_MODULE_SIG) += module_signing.o
+obj-$(CONFIG_MODULE_SIG_FORMAT) += module_signing.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
obj-$(CONFIG_CRASH_CORE) += crash_core.o
diff --git a/kernel/module.c b/kernel/module.c
index 40f983cbea81..52921fccb51a 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -19,6 +19,7 @@
#include <linux/export.h>
#include <linux/extable.h>
#include <linux/moduleloader.h>
+#include <linux/module_signature.h>
#include <linux/trace_events.h>
#include <linux/init.h>
#include <linux/kallsyms.h>
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index 937c844bee4a..204c60d4cc9f 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -11,36 +11,38 @@
#include <linux/kernel.h>
#include <linux/errno.h>
+#include <linux/module_signature.h>
#include <linux/string.h>
#include <linux/verification.h>
#include <crypto/public_key.h>
#include "module-internal.h"
-enum pkey_id_type {
- PKEY_ID_PGP, /* OpenPGP generated key ID */
- PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */
- PKEY_ID_PKCS7, /* Signature in PKCS#7 message */
-};
-
-/*
- * Module signature information block.
- *
- * The constituents of the signature section are, in order:
+/**
+ * validate_module_sig - validate that the given signature is sane
*
- * - Signer's name
- * - Key identifier
- * - Signature data
- * - Information block
+ * @ms: Signature to validate.
+ * @file_len: Size of the file to which @ms is appended.
*/
-struct module_signature {
- u8 algo; /* Public-key crypto algorithm [0] */
- u8 hash; /* Digest algorithm [0] */
- u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */
- u8 signer_len; /* Length of signer's name [0] */
- u8 key_id_len; /* Length of key identifier [0] */
- u8 __pad[3];
- __be32 sig_len; /* Length of signature data */
-};
+int validate_module_sig(const struct module_signature *ms, size_t file_len)
+{
+ if (be32_to_cpu(ms->sig_len) >= file_len - sizeof(*ms))
+ return -EBADMSG;
+ else if (ms->id_type != PKEY_ID_PKCS7) {
+ pr_err("Module is not signed with expected PKCS#7 message\n");
+ return -ENOPKG;
+ } else if (ms->algo != 0 ||
+ ms->hash != 0 ||
+ ms->signer_len != 0 ||
+ ms->key_id_len != 0 ||
+ ms->__pad[0] != 0 ||
+ ms->__pad[1] != 0 ||
+ ms->__pad[2] != 0) {
+ pr_err("PKCS#7 signature info has unexpected non-zero params\n");
+ return -EBADMSG;
+ }
+
+ return 0;
+}
/*
* Verify the signature on a module.
@@ -49,6 +51,7 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
{
struct module_signature ms;
size_t modlen = *_modlen, sig_len;
+ int ret;
pr_devel("==>%s(,%zu)\n", __func__, modlen);
@@ -56,30 +59,15 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
return -EBADMSG;
memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
- modlen -= sizeof(ms);
+
+ ret = validate_module_sig(&ms, modlen);
+ if (ret)
+ return ret;
sig_len = be32_to_cpu(ms.sig_len);
- if (sig_len >= modlen)
- return -EBADMSG;
- modlen -= sig_len;
+ modlen -= sig_len + sizeof(ms);
*_modlen = modlen;
- if (ms.id_type != PKEY_ID_PKCS7) {
- pr_err("Module is not signed with expected PKCS#7 message\n");
- return -ENOPKG;
- }
-
- if (ms.algo != 0 ||
- ms.hash != 0 ||
- ms.signer_len != 0 ||
- ms.key_id_len != 0 ||
- ms.__pad[0] != 0 ||
- ms.__pad[1] != 0 ||
- ms.__pad[2] != 0) {
- pr_err("PKCS#7 signature info has unexpected non-zero params\n");
- return -EBADMSG;
- }
-
return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
NULL, VERIFYING_MODULE_SIGNATURE,
NULL, NULL);
--
2.14.1
[toc] | [prev] | [next] | [standalone]
| From | AKASHI Takahiro <takahiro.akashi@linaro.org> |
|---|---|
| Date | 2017-08-24 10:30 +0200 |
| Subject | [PATCH 09/14] arm64: kexec_file: add sha256 digest check in purgatory |
| Message-ID | <uhVGx-405-7@gated-at.bofh.it> |
| In reply to | #1718948 |
Most of sha256 code is based on crypto/sha256-glue.c, particularly using
non-neon version.
Please note that we won't be able to re-use lib/mem*.S for purgatory
because unaligned memory access is not allowed in purgatory where mmu
is turned off.
Since purgatory is not linked with the other part of kernel, care must be
taken of selecting an appropriate set of compiler options in order to
prevent undefined symbol references from being generated.
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/crypto/sha256-core.S_shipped | 2 +
arch/arm64/purgatory/Makefile | 21 ++++++++-
arch/arm64/purgatory/entry.S | 13 ++++++
arch/arm64/purgatory/purgatory.c | 20 +++++++++
arch/arm64/purgatory/sha256-core.S | 1 +
arch/arm64/purgatory/sha256.c | 79 +++++++++++++++++++++++++++++++++
arch/arm64/purgatory/sha256.h | 1 +
arch/arm64/purgatory/string.c | 32 +++++++++++++
arch/arm64/purgatory/string.h | 5 +++
9 files changed, 173 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/purgatory/purgatory.c
create mode 100644 arch/arm64/purgatory/sha256-core.S
create mode 100644 arch/arm64/purgatory/sha256.c
create mode 100644 arch/arm64/purgatory/sha256.h
create mode 100644 arch/arm64/purgatory/string.c
create mode 100644 arch/arm64/purgatory/string.h
diff --git a/arch/arm64/crypto/sha256-core.S_shipped b/arch/arm64/crypto/sha256-core.S_shipped
index 3ce82cc860bc..9ce7419c9152 100644
--- a/arch/arm64/crypto/sha256-core.S_shipped
+++ b/arch/arm64/crypto/sha256-core.S_shipped
@@ -1210,6 +1210,7 @@ sha256_block_armv8:
ret
.size sha256_block_armv8,.-sha256_block_armv8
#endif
+#ifndef __PURGATORY__
#ifdef __KERNEL__
.globl sha256_block_neon
#endif
@@ -2056,6 +2057,7 @@ sha256_block_neon:
add sp,sp,#16*4+16
ret
.size sha256_block_neon,.-sha256_block_neon
+#endif
#ifndef __KERNEL__
.comm OPENSSL_armcap_P,4,4
#endif
diff --git a/arch/arm64/purgatory/Makefile b/arch/arm64/purgatory/Makefile
index c2127a2cbd51..d9b38be31e0a 100644
--- a/arch/arm64/purgatory/Makefile
+++ b/arch/arm64/purgatory/Makefile
@@ -1,14 +1,33 @@
OBJECT_FILES_NON_STANDARD := y
-purgatory-y := entry.o
+purgatory-y := entry.o purgatory.o sha256.o sha256-core.o string.o
targets += $(purgatory-y)
PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y))
+# Purgatory is expected to be ET_REL, not an executable
LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined \
-nostdlib -z nodefaultlib
+
targets += purgatory.ro
+GCOV_PROFILE := n
+KASAN_SANITIZE := n
+KCOV_INSTRUMENT := n
+
+# Some kernel configurations may generate additional code containing
+# undefined symbols, like _mcount for ftrace and __stack_chk_guard
+# for stack-protector. Those should be removed from purgatory.
+
+CFLAGS_REMOVE_purgatory.o = -pg
+CFLAGS_REMOVE_sha256.o = -pg
+CFLAGS_REMOVE_string.o = -pg
+
+NO_PROTECTOR := $(call cc-option, -fno-stack-protector)
+KBUILD_CFLAGS += $(NO_PROTECTOR)
+
+KBUILD_AFLAGS += -D__PURGATORY__
+
$(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
$(call if_changed,ld)
diff --git a/arch/arm64/purgatory/entry.S b/arch/arm64/purgatory/entry.S
index bc4e6b3bf8a1..74d028b838bd 100644
--- a/arch/arm64/purgatory/entry.S
+++ b/arch/arm64/purgatory/entry.S
@@ -6,6 +6,11 @@
.text
ENTRY(purgatory_start)
+ adr x19, .Lstack
+ mov sp, x19
+
+ bl purgatory
+
/* Start new image. */
ldr x17, arm64_kernel_entry
ldr x0, arm64_dtb_addr
@@ -15,6 +20,14 @@ ENTRY(purgatory_start)
br x17
END(purgatory_start)
+.ltorg
+
+.align 4
+ .rept 256
+ .quad 0
+ .endr
+.Lstack:
+
.data
.align 3
diff --git a/arch/arm64/purgatory/purgatory.c b/arch/arm64/purgatory/purgatory.c
new file mode 100644
index 000000000000..7fcbefa786bc
--- /dev/null
+++ b/arch/arm64/purgatory/purgatory.c
@@ -0,0 +1,20 @@
+/*
+ * purgatory: Runs between two kernels
+ *
+ * Copyright (c) 2017 Linaro Limited
+ * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ */
+
+#include "sha256.h"
+
+void purgatory(void)
+{
+ int ret;
+
+ ret = verify_sha256_digest();
+ if (ret) {
+ /* loop forever */
+ for (;;)
+ ;
+ }
+}
diff --git a/arch/arm64/purgatory/sha256-core.S b/arch/arm64/purgatory/sha256-core.S
new file mode 100644
index 000000000000..24f5ce25b61e
--- /dev/null
+++ b/arch/arm64/purgatory/sha256-core.S
@@ -0,0 +1 @@
+#include "../crypto/sha256-core.S_shipped"
diff --git a/arch/arm64/purgatory/sha256.c b/arch/arm64/purgatory/sha256.c
new file mode 100644
index 000000000000..5d20d81767e3
--- /dev/null
+++ b/arch/arm64/purgatory/sha256.c
@@ -0,0 +1,79 @@
+#include <linux/kexec.h>
+#include <linux/purgatory.h>
+#include <linux/types.h>
+
+/*
+ * Under KASAN, those are defined as un-instrumented version, __memxxx()
+ */
+#undef memcmp
+#undef memcpy
+#undef memset
+
+#include "string.h"
+#include <crypto/hash.h>
+#include <crypto/sha.h>
+#include <crypto/sha256_base.h>
+
+u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE] __section(.kexec-purgatory);
+struct kexec_sha_region purgatory_sha_regions[KEXEC_SEGMENT_MAX]
+ __section(.kexec-purgatory);
+
+asmlinkage void sha256_block_data_order(u32 *digest, const void *data,
+ unsigned int num_blks);
+
+static int sha256_init(struct shash_desc *desc)
+{
+ return sha256_base_init(desc);
+}
+
+static int sha256_update(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ return sha256_base_do_update(desc, data, len,
+ (sha256_block_fn *)sha256_block_data_order);
+}
+
+static int __sha256_base_finish(struct shash_desc *desc, u8 *out)
+{
+ /* we can't do crypto_shash_digestsize(desc->tfm) */
+ unsigned int digest_size = 32;
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+ __be32 *digest = (__be32 *)out;
+ int i;
+
+ for (i = 0; digest_size > 0; i++, digest_size -= sizeof(__be32))
+ put_unaligned_be32(sctx->state[i], digest++);
+
+ *sctx = (struct sha256_state){};
+ return 0;
+}
+
+static int sha256_final(struct shash_desc *desc, u8 *out)
+{
+ sha256_base_do_finalize(desc,
+ (sha256_block_fn *)sha256_block_data_order);
+
+ return __sha256_base_finish(desc, out);
+}
+
+int verify_sha256_digest(void)
+{
+ char __sha256_desc[sizeof(struct shash_desc) +
+ sizeof(struct sha256_state)] CRYPTO_MINALIGN_ATTR;
+ struct shash_desc *desc = (struct shash_desc *)__sha256_desc;
+ struct kexec_sha_region *ptr, *end;
+ u8 digest[SHA256_DIGEST_SIZE];
+
+ sha256_init(desc);
+
+ end = purgatory_sha_regions + ARRAY_SIZE(purgatory_sha_regions);
+ for (ptr = purgatory_sha_regions; ptr < end; ptr++)
+ sha256_update(desc, (uint8_t *)(ptr->start), ptr->len);
+
+ sha256_final(desc, digest);
+
+ if (memcmp(digest, purgatory_sha256_digest, sizeof(digest)))
+ return 1;
+
+ return 0;
+}
diff --git a/arch/arm64/purgatory/sha256.h b/arch/arm64/purgatory/sha256.h
new file mode 100644
index 000000000000..54dc3c33c469
--- /dev/null
+++ b/arch/arm64/purgatory/sha256.h
@@ -0,0 +1 @@
+extern int verify_sha256_digest(void);
diff --git a/arch/arm64/purgatory/string.c b/arch/arm64/purgatory/string.c
new file mode 100644
index 000000000000..33233a210a65
--- /dev/null
+++ b/arch/arm64/purgatory/string.c
@@ -0,0 +1,32 @@
+#include <linux/types.h>
+
+void *memcpy(void *dst, const void *src, size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ ((u8 *)dst)[i] = ((u8 *)src)[i];
+
+ return NULL;
+}
+
+void *memset(void *dst, int c, size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ ((u8 *)dst)[i] = (u8)c;
+
+ return NULL;
+}
+
+int memcmp(const void *src, const void *dst, size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if (*(char *)src != *(char *)dst)
+ return 1;
+
+ return 0;
+}
diff --git a/arch/arm64/purgatory/string.h b/arch/arm64/purgatory/string.h
new file mode 100644
index 000000000000..cb5f68dd84ef
--- /dev/null
+++ b/arch/arm64/purgatory/string.h
@@ -0,0 +1,5 @@
+#include <linux/types.h>
+
+int memcmp(const void *s1, const void *s2, size_t len);
+void *memcpy(void *dst, const void *src, size_t len);
+void *memset(void *dst, int c, size_t len);
--
2.14.1
[toc] | [prev] | [next] | [standalone]
| From | Ard Biesheuvel <ard.biesheuvel@linaro.org> |
|---|---|
| Date | 2017-08-24 11:20 +0200 |
| Subject | Re: [PATCH 09/14] arm64: kexec_file: add sha256 digest check in purgatory |
| Message-ID | <uhWsV-4xQ-7@gated-at.bofh.it> |
| In reply to | #1718964 |
On 24 August 2017 at 09:18, AKASHI Takahiro <takahiro.akashi@linaro.org> wrote:
> Most of sha256 code is based on crypto/sha256-glue.c, particularly using
> non-neon version.
>
> Please note that we won't be able to re-use lib/mem*.S for purgatory
> because unaligned memory access is not allowed in purgatory where mmu
> is turned off.
>
> Since purgatory is not linked with the other part of kernel, care must be
> taken of selecting an appropriate set of compiler options in order to
> prevent undefined symbol references from being generated.
>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> arch/arm64/crypto/sha256-core.S_shipped | 2 +
> arch/arm64/purgatory/Makefile | 21 ++++++++-
> arch/arm64/purgatory/entry.S | 13 ++++++
> arch/arm64/purgatory/purgatory.c | 20 +++++++++
> arch/arm64/purgatory/sha256-core.S | 1 +
> arch/arm64/purgatory/sha256.c | 79 +++++++++++++++++++++++++++++++++
> arch/arm64/purgatory/sha256.h | 1 +
> arch/arm64/purgatory/string.c | 32 +++++++++++++
> arch/arm64/purgatory/string.h | 5 +++
> 9 files changed, 173 insertions(+), 1 deletion(-)
> create mode 100644 arch/arm64/purgatory/purgatory.c
> create mode 100644 arch/arm64/purgatory/sha256-core.S
> create mode 100644 arch/arm64/purgatory/sha256.c
> create mode 100644 arch/arm64/purgatory/sha256.h
> create mode 100644 arch/arm64/purgatory/string.c
> create mode 100644 arch/arm64/purgatory/string.h
>
> diff --git a/arch/arm64/crypto/sha256-core.S_shipped b/arch/arm64/crypto/sha256-core.S_shipped
> index 3ce82cc860bc..9ce7419c9152 100644
> --- a/arch/arm64/crypto/sha256-core.S_shipped
> +++ b/arch/arm64/crypto/sha256-core.S_shipped
> @@ -1210,6 +1210,7 @@ sha256_block_armv8:
> ret
> .size sha256_block_armv8,.-sha256_block_armv8
> #endif
> +#ifndef __PURGATORY__
> #ifdef __KERNEL__
> .globl sha256_block_neon
> #endif
> @@ -2056,6 +2057,7 @@ sha256_block_neon:
> add sp,sp,#16*4+16
> ret
> .size sha256_block_neon,.-sha256_block_neon
> +#endif
> #ifndef __KERNEL__
> .comm OPENSSL_armcap_P,4,4
> #endif
Could you please try to find another way to address this?
sha256-core.S_shipped is generated code from the accompanying Perl
script, and that script is kept in sync with upstream OpenSSL. Also,
the performance delta between the generic code is not /that/
spectacular, so we may simply use that instead.
> diff --git a/arch/arm64/purgatory/Makefile b/arch/arm64/purgatory/Makefile
> index c2127a2cbd51..d9b38be31e0a 100644
> --- a/arch/arm64/purgatory/Makefile
> +++ b/arch/arm64/purgatory/Makefile
> @@ -1,14 +1,33 @@
> OBJECT_FILES_NON_STANDARD := y
>
> -purgatory-y := entry.o
> +purgatory-y := entry.o purgatory.o sha256.o sha256-core.o string.o
>
> targets += $(purgatory-y)
> PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y))
>
> +# Purgatory is expected to be ET_REL, not an executable
> LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined \
> -nostdlib -z nodefaultlib
> +
> targets += purgatory.ro
>
> +GCOV_PROFILE := n
> +KASAN_SANITIZE := n
> +KCOV_INSTRUMENT := n
> +
> +# Some kernel configurations may generate additional code containing
> +# undefined symbols, like _mcount for ftrace and __stack_chk_guard
> +# for stack-protector. Those should be removed from purgatory.
> +
> +CFLAGS_REMOVE_purgatory.o = -pg
> +CFLAGS_REMOVE_sha256.o = -pg
> +CFLAGS_REMOVE_string.o = -pg
> +
> +NO_PROTECTOR := $(call cc-option, -fno-stack-protector)
> +KBUILD_CFLAGS += $(NO_PROTECTOR)
> +
> +KBUILD_AFLAGS += -D__PURGATORY__
> +
> $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
> $(call if_changed,ld)
>
> diff --git a/arch/arm64/purgatory/entry.S b/arch/arm64/purgatory/entry.S
> index bc4e6b3bf8a1..74d028b838bd 100644
> --- a/arch/arm64/purgatory/entry.S
> +++ b/arch/arm64/purgatory/entry.S
> @@ -6,6 +6,11 @@
> .text
>
> ENTRY(purgatory_start)
> + adr x19, .Lstack
> + mov sp, x19
> +
> + bl purgatory
> +
> /* Start new image. */
> ldr x17, arm64_kernel_entry
> ldr x0, arm64_dtb_addr
> @@ -15,6 +20,14 @@ ENTRY(purgatory_start)
> br x17
> END(purgatory_start)
>
> +.ltorg
> +
> +.align 4
> + .rept 256
> + .quad 0
> + .endr
> +.Lstack:
> +
> .data
>
> .align 3
> diff --git a/arch/arm64/purgatory/purgatory.c b/arch/arm64/purgatory/purgatory.c
> new file mode 100644
> index 000000000000..7fcbefa786bc
> --- /dev/null
> +++ b/arch/arm64/purgatory/purgatory.c
> @@ -0,0 +1,20 @@
> +/*
> + * purgatory: Runs between two kernels
> + *
> + * Copyright (c) 2017 Linaro Limited
> + * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> + */
> +
> +#include "sha256.h"
> +
> +void purgatory(void)
> +{
> + int ret;
> +
> + ret = verify_sha256_digest();
> + if (ret) {
> + /* loop forever */
> + for (;;)
> + ;
> + }
> +}
> diff --git a/arch/arm64/purgatory/sha256-core.S b/arch/arm64/purgatory/sha256-core.S
> new file mode 100644
> index 000000000000..24f5ce25b61e
> --- /dev/null
> +++ b/arch/arm64/purgatory/sha256-core.S
> @@ -0,0 +1 @@
> +#include "../crypto/sha256-core.S_shipped"
> diff --git a/arch/arm64/purgatory/sha256.c b/arch/arm64/purgatory/sha256.c
> new file mode 100644
> index 000000000000..5d20d81767e3
> --- /dev/null
> +++ b/arch/arm64/purgatory/sha256.c
> @@ -0,0 +1,79 @@
> +#include <linux/kexec.h>
> +#include <linux/purgatory.h>
> +#include <linux/types.h>
> +
> +/*
> + * Under KASAN, those are defined as un-instrumented version, __memxxx()
> + */
> +#undef memcmp
> +#undef memcpy
> +#undef memset
> +
> +#include "string.h"
> +#include <crypto/hash.h>
> +#include <crypto/sha.h>
> +#include <crypto/sha256_base.h>
> +
> +u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE] __section(.kexec-purgatory);
> +struct kexec_sha_region purgatory_sha_regions[KEXEC_SEGMENT_MAX]
> + __section(.kexec-purgatory);
> +
> +asmlinkage void sha256_block_data_order(u32 *digest, const void *data,
> + unsigned int num_blks);
> +
> +static int sha256_init(struct shash_desc *desc)
> +{
> + return sha256_base_init(desc);
> +}
> +
> +static int sha256_update(struct shash_desc *desc, const u8 *data,
> + unsigned int len)
> +{
> + return sha256_base_do_update(desc, data, len,
> + (sha256_block_fn *)sha256_block_data_order);
> +}
> +
> +static int __sha256_base_finish(struct shash_desc *desc, u8 *out)
> +{
> + /* we can't do crypto_shash_digestsize(desc->tfm) */
> + unsigned int digest_size = 32;
> + struct sha256_state *sctx = shash_desc_ctx(desc);
> + __be32 *digest = (__be32 *)out;
> + int i;
> +
> + for (i = 0; digest_size > 0; i++, digest_size -= sizeof(__be32))
> + put_unaligned_be32(sctx->state[i], digest++);
> +
> + *sctx = (struct sha256_state){};
> + return 0;
> +}
> +
> +static int sha256_final(struct shash_desc *desc, u8 *out)
> +{
> + sha256_base_do_finalize(desc,
> + (sha256_block_fn *)sha256_block_data_order);
> +
> + return __sha256_base_finish(desc, out);
> +}
> +
> +int verify_sha256_digest(void)
> +{
> + char __sha256_desc[sizeof(struct shash_desc) +
> + sizeof(struct sha256_state)] CRYPTO_MINALIGN_ATTR;
> + struct shash_desc *desc = (struct shash_desc *)__sha256_desc;
> + struct kexec_sha_region *ptr, *end;
> + u8 digest[SHA256_DIGEST_SIZE];
> +
> + sha256_init(desc);
> +
> + end = purgatory_sha_regions + ARRAY_SIZE(purgatory_sha_regions);
> + for (ptr = purgatory_sha_regions; ptr < end; ptr++)
> + sha256_update(desc, (uint8_t *)(ptr->start), ptr->len);
> +
> + sha256_final(desc, digest);
> +
> + if (memcmp(digest, purgatory_sha256_digest, sizeof(digest)))
> + return 1;
> +
> + return 0;
> +}
> diff --git a/arch/arm64/purgatory/sha256.h b/arch/arm64/purgatory/sha256.h
> new file mode 100644
> index 000000000000..54dc3c33c469
> --- /dev/null
> +++ b/arch/arm64/purgatory/sha256.h
> @@ -0,0 +1 @@
> +extern int verify_sha256_digest(void);
> diff --git a/arch/arm64/purgatory/string.c b/arch/arm64/purgatory/string.c
> new file mode 100644
> index 000000000000..33233a210a65
> --- /dev/null
> +++ b/arch/arm64/purgatory/string.c
> @@ -0,0 +1,32 @@
> +#include <linux/types.h>
> +
> +void *memcpy(void *dst, const void *src, size_t len)
> +{
> + int i;
> +
> + for (i = 0; i < len; i++)
> + ((u8 *)dst)[i] = ((u8 *)src)[i];
> +
> + return NULL;
> +}
> +
> +void *memset(void *dst, int c, size_t len)
> +{
> + int i;
> +
> + for (i = 0; i < len; i++)
> + ((u8 *)dst)[i] = (u8)c;
> +
> + return NULL;
> +}
> +
> +int memcmp(const void *src, const void *dst, size_t len)
> +{
> + int i;
> +
> + for (i = 0; i < len; i++)
> + if (*(char *)src != *(char *)dst)
> + return 1;
> +
> + return 0;
> +}
> diff --git a/arch/arm64/purgatory/string.h b/arch/arm64/purgatory/string.h
> new file mode 100644
> index 000000000000..cb5f68dd84ef
> --- /dev/null
> +++ b/arch/arm64/purgatory/string.h
> @@ -0,0 +1,5 @@
> +#include <linux/types.h>
> +
> +int memcmp(const void *s1, const void *s2, size_t len);
> +void *memcpy(void *dst, const void *src, size_t len);
> +void *memset(void *dst, int c, size_t len);
> --
> 2.14.1
>
[toc] | [prev] | [next] | [standalone]
| From | AKASHI Takahiro <takahiro.akashi@linaro.org> |
|---|---|
| Date | 2017-08-25 03:30 +0200 |
| Subject | Re: [PATCH 09/14] arm64: kexec_file: add sha256 digest check in purgatory |
| Message-ID | <uibBD-5Ur-13@gated-at.bofh.it> |
| In reply to | #1719045 |
On Thu, Aug 24, 2017 at 10:13:49AM +0100, Ard Biesheuvel wrote:
> On 24 August 2017 at 09:18, AKASHI Takahiro <takahiro.akashi@linaro.org> wrote:
> > Most of sha256 code is based on crypto/sha256-glue.c, particularly using
> > non-neon version.
> >
> > Please note that we won't be able to re-use lib/mem*.S for purgatory
> > because unaligned memory access is not allowed in purgatory where mmu
> > is turned off.
> >
> > Since purgatory is not linked with the other part of kernel, care must be
> > taken of selecting an appropriate set of compiler options in order to
> > prevent undefined symbol references from being generated.
> >
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > Cc: Catalin Marinas <catalin.marinas@arm.com>
> > Cc: Will Deacon <will.deacon@arm.com>
> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > ---
> > arch/arm64/crypto/sha256-core.S_shipped | 2 +
> > arch/arm64/purgatory/Makefile | 21 ++++++++-
> > arch/arm64/purgatory/entry.S | 13 ++++++
> > arch/arm64/purgatory/purgatory.c | 20 +++++++++
> > arch/arm64/purgatory/sha256-core.S | 1 +
> > arch/arm64/purgatory/sha256.c | 79 +++++++++++++++++++++++++++++++++
> > arch/arm64/purgatory/sha256.h | 1 +
> > arch/arm64/purgatory/string.c | 32 +++++++++++++
> > arch/arm64/purgatory/string.h | 5 +++
> > 9 files changed, 173 insertions(+), 1 deletion(-)
> > create mode 100644 arch/arm64/purgatory/purgatory.c
> > create mode 100644 arch/arm64/purgatory/sha256-core.S
> > create mode 100644 arch/arm64/purgatory/sha256.c
> > create mode 100644 arch/arm64/purgatory/sha256.h
> > create mode 100644 arch/arm64/purgatory/string.c
> > create mode 100644 arch/arm64/purgatory/string.h
> >
> > diff --git a/arch/arm64/crypto/sha256-core.S_shipped b/arch/arm64/crypto/sha256-core.S_shipped
> > index 3ce82cc860bc..9ce7419c9152 100644
> > --- a/arch/arm64/crypto/sha256-core.S_shipped
> > +++ b/arch/arm64/crypto/sha256-core.S_shipped
> > @@ -1210,6 +1210,7 @@ sha256_block_armv8:
> > ret
> > .size sha256_block_armv8,.-sha256_block_armv8
> > #endif
> > +#ifndef __PURGATORY__
> > #ifdef __KERNEL__
> > .globl sha256_block_neon
> > #endif
> > @@ -2056,6 +2057,7 @@ sha256_block_neon:
> > add sp,sp,#16*4+16
> > ret
> > .size sha256_block_neon,.-sha256_block_neon
> > +#endif
> > #ifndef __KERNEL__
> > .comm OPENSSL_armcap_P,4,4
> > #endif
>
> Could you please try to find another way to address this?
> sha256-core.S_shipped is generated code from the accompanying Perl
> script, and that script is kept in sync with upstream OpenSSL. Also,
> the performance delta between the generic code is not /that/
> spectacular, so we may simply use that instead.
I see.
Do you mean that "generic" code is a C source?
Thanks,
-Takahiro AKASHI
>
> > diff --git a/arch/arm64/purgatory/Makefile b/arch/arm64/purgatory/Makefile
> > index c2127a2cbd51..d9b38be31e0a 100644
> > --- a/arch/arm64/purgatory/Makefile
> > +++ b/arch/arm64/purgatory/Makefile
> > @@ -1,14 +1,33 @@
> > OBJECT_FILES_NON_STANDARD := y
> >
> > -purgatory-y := entry.o
> > +purgatory-y := entry.o purgatory.o sha256.o sha256-core.o string.o
> >
> > targets += $(purgatory-y)
> > PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y))
> >
> > +# Purgatory is expected to be ET_REL, not an executable
> > LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined \
> > -nostdlib -z nodefaultlib
> > +
> > targets += purgatory.ro
> >
> > +GCOV_PROFILE := n
> > +KASAN_SANITIZE := n
> > +KCOV_INSTRUMENT := n
> > +
> > +# Some kernel configurations may generate additional code containing
> > +# undefined symbols, like _mcount for ftrace and __stack_chk_guard
> > +# for stack-protector. Those should be removed from purgatory.
> > +
> > +CFLAGS_REMOVE_purgatory.o = -pg
> > +CFLAGS_REMOVE_sha256.o = -pg
> > +CFLAGS_REMOVE_string.o = -pg
> > +
> > +NO_PROTECTOR := $(call cc-option, -fno-stack-protector)
> > +KBUILD_CFLAGS += $(NO_PROTECTOR)
> > +
> > +KBUILD_AFLAGS += -D__PURGATORY__
> > +
> > $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
> > $(call if_changed,ld)
> >
> > diff --git a/arch/arm64/purgatory/entry.S b/arch/arm64/purgatory/entry.S
> > index bc4e6b3bf8a1..74d028b838bd 100644
> > --- a/arch/arm64/purgatory/entry.S
> > +++ b/arch/arm64/purgatory/entry.S
> > @@ -6,6 +6,11 @@
> > .text
> >
> > ENTRY(purgatory_start)
> > + adr x19, .Lstack
> > + mov sp, x19
> > +
> > + bl purgatory
> > +
> > /* Start new image. */
> > ldr x17, arm64_kernel_entry
> > ldr x0, arm64_dtb_addr
> > @@ -15,6 +20,14 @@ ENTRY(purgatory_start)
> > br x17
> > END(purgatory_start)
> >
> > +.ltorg
> > +
> > +.align 4
> > + .rept 256
> > + .quad 0
> > + .endr
> > +.Lstack:
> > +
> > .data
> >
> > .align 3
> > diff --git a/arch/arm64/purgatory/purgatory.c b/arch/arm64/purgatory/purgatory.c
> > new file mode 100644
> > index 000000000000..7fcbefa786bc
> > --- /dev/null
> > +++ b/arch/arm64/purgatory/purgatory.c
> > @@ -0,0 +1,20 @@
> > +/*
> > + * purgatory: Runs between two kernels
> > + *
> > + * Copyright (c) 2017 Linaro Limited
> > + * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > + */
> > +
> > +#include "sha256.h"
> > +
> > +void purgatory(void)
> > +{
> > + int ret;
> > +
> > + ret = verify_sha256_digest();
> > + if (ret) {
> > + /* loop forever */
> > + for (;;)
> > + ;
> > + }
> > +}
> > diff --git a/arch/arm64/purgatory/sha256-core.S b/arch/arm64/purgatory/sha256-core.S
> > new file mode 100644
> > index 000000000000..24f5ce25b61e
> > --- /dev/null
> > +++ b/arch/arm64/purgatory/sha256-core.S
> > @@ -0,0 +1 @@
> > +#include "../crypto/sha256-core.S_shipped"
> > diff --git a/arch/arm64/purgatory/sha256.c b/arch/arm64/purgatory/sha256.c
> > new file mode 100644
> > index 000000000000..5d20d81767e3
> > --- /dev/null
> > +++ b/arch/arm64/purgatory/sha256.c
> > @@ -0,0 +1,79 @@
> > +#include <linux/kexec.h>
> > +#include <linux/purgatory.h>
> > +#include <linux/types.h>
> > +
> > +/*
> > + * Under KASAN, those are defined as un-instrumented version, __memxxx()
> > + */
> > +#undef memcmp
> > +#undef memcpy
> > +#undef memset
> > +
> > +#include "string.h"
> > +#include <crypto/hash.h>
> > +#include <crypto/sha.h>
> > +#include <crypto/sha256_base.h>
> > +
> > +u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE] __section(.kexec-purgatory);
> > +struct kexec_sha_region purgatory_sha_regions[KEXEC_SEGMENT_MAX]
> > + __section(.kexec-purgatory);
> > +
> > +asmlinkage void sha256_block_data_order(u32 *digest, const void *data,
> > + unsigned int num_blks);
> > +
> > +static int sha256_init(struct shash_desc *desc)
> > +{
> > + return sha256_base_init(desc);
> > +}
> > +
> > +static int sha256_update(struct shash_desc *desc, const u8 *data,
> > + unsigned int len)
> > +{
> > + return sha256_base_do_update(desc, data, len,
> > + (sha256_block_fn *)sha256_block_data_order);
> > +}
> > +
> > +static int __sha256_base_finish(struct shash_desc *desc, u8 *out)
> > +{
> > + /* we can't do crypto_shash_digestsize(desc->tfm) */
> > + unsigned int digest_size = 32;
> > + struct sha256_state *sctx = shash_desc_ctx(desc);
> > + __be32 *digest = (__be32 *)out;
> > + int i;
> > +
> > + for (i = 0; digest_size > 0; i++, digest_size -= sizeof(__be32))
> > + put_unaligned_be32(sctx->state[i], digest++);
> > +
> > + *sctx = (struct sha256_state){};
> > + return 0;
> > +}
> > +
> > +static int sha256_final(struct shash_desc *desc, u8 *out)
> > +{
> > + sha256_base_do_finalize(desc,
> > + (sha256_block_fn *)sha256_block_data_order);
> > +
> > + return __sha256_base_finish(desc, out);
> > +}
> > +
> > +int verify_sha256_digest(void)
> > +{
> > + char __sha256_desc[sizeof(struct shash_desc) +
> > + sizeof(struct sha256_state)] CRYPTO_MINALIGN_ATTR;
> > + struct shash_desc *desc = (struct shash_desc *)__sha256_desc;
> > + struct kexec_sha_region *ptr, *end;
> > + u8 digest[SHA256_DIGEST_SIZE];
> > +
> > + sha256_init(desc);
> > +
> > + end = purgatory_sha_regions + ARRAY_SIZE(purgatory_sha_regions);
> > + for (ptr = purgatory_sha_regions; ptr < end; ptr++)
> > + sha256_update(desc, (uint8_t *)(ptr->start), ptr->len);
> > +
> > + sha256_final(desc, digest);
> > +
> > + if (memcmp(digest, purgatory_sha256_digest, sizeof(digest)))
> > + return 1;
> > +
> > + return 0;
> > +}
> > diff --git a/arch/arm64/purgatory/sha256.h b/arch/arm64/purgatory/sha256.h
> > new file mode 100644
> > index 000000000000..54dc3c33c469
> > --- /dev/null
> > +++ b/arch/arm64/purgatory/sha256.h
> > @@ -0,0 +1 @@
> > +extern int verify_sha256_digest(void);
> > diff --git a/arch/arm64/purgatory/string.c b/arch/arm64/purgatory/string.c
> > new file mode 100644
> > index 000000000000..33233a210a65
> > --- /dev/null
> > +++ b/arch/arm64/purgatory/string.c
> > @@ -0,0 +1,32 @@
> > +#include <linux/types.h>
> > +
> > +void *memcpy(void *dst, const void *src, size_t len)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < len; i++)
> > + ((u8 *)dst)[i] = ((u8 *)src)[i];
> > +
> > + return NULL;
> > +}
> > +
> > +void *memset(void *dst, int c, size_t len)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < len; i++)
> > + ((u8 *)dst)[i] = (u8)c;
> > +
> > + return NULL;
> > +}
> > +
> > +int memcmp(const void *src, const void *dst, size_t len)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < len; i++)
> > + if (*(char *)src != *(char *)dst)
> > + return 1;
> > +
> > + return 0;
> > +}
> > diff --git a/arch/arm64/purgatory/string.h b/arch/arm64/purgatory/string.h
> > new file mode 100644
> > index 000000000000..cb5f68dd84ef
> > --- /dev/null
> > +++ b/arch/arm64/purgatory/string.h
> > @@ -0,0 +1,5 @@
> > +#include <linux/types.h>
> > +
> > +int memcmp(const void *s1, const void *s2, size_t len);
> > +void *memcpy(void *dst, const void *src, size_t len);
> > +void *memset(void *dst, int c, size_t len);
> > --
> > 2.14.1
> >
[toc] | [prev] | [next] | [standalone]
| From | Mark Rutland <mark.rutland@arm.com> |
|---|---|
| Date | 2017-08-24 19:10 +0200 |
| Subject | Re: [PATCH 09/14] arm64: kexec_file: add sha256 digest check in purgatory |
| Message-ID | <ui3NM-VH-17@gated-at.bofh.it> |
| In reply to | #1718964 |
On Thu, Aug 24, 2017 at 05:18:06PM +0900, AKASHI Takahiro wrote:
> Most of sha256 code is based on crypto/sha256-glue.c, particularly using
> non-neon version.
>
> Please note that we won't be able to re-use lib/mem*.S for purgatory
> because unaligned memory access is not allowed in purgatory where mmu
> is turned off.
>
> Since purgatory is not linked with the other part of kernel, care must be
> taken of selecting an appropriate set of compiler options in order to
> prevent undefined symbol references from being generated.
What is the point in performing this check in the purgatory code, when
this will presumably have been checked when the image is loaded?
[...]
> diff --git a/arch/arm64/purgatory/entry.S b/arch/arm64/purgatory/entry.S
> index bc4e6b3bf8a1..74d028b838bd 100644
> --- a/arch/arm64/purgatory/entry.S
> +++ b/arch/arm64/purgatory/entry.S
> @@ -6,6 +6,11 @@
> .text
>
> ENTRY(purgatory_start)
> + adr x19, .Lstack
> + mov sp, x19
> +
> + bl purgatory
> +
> /* Start new image. */
> ldr x17, arm64_kernel_entry
> ldr x0, arm64_dtb_addr
> @@ -15,6 +20,14 @@ ENTRY(purgatory_start)
> br x17
> END(purgatory_start)
>
> +.ltorg
> +
> +.align 4
> + .rept 256
> + .quad 0
> + .endr
> +.Lstack:
> +
> .data
Why is the stack in .text?
Does this need to be zeroed?
If it does, why not something like:
.fill PURGATORY_STACK_SIZE 1, 0
>
> .align 3
> diff --git a/arch/arm64/purgatory/purgatory.c b/arch/arm64/purgatory/purgatory.c
> new file mode 100644
> index 000000000000..7fcbefa786bc
> --- /dev/null
> +++ b/arch/arm64/purgatory/purgatory.c
> @@ -0,0 +1,20 @@
> +/*
> + * purgatory: Runs between two kernels
> + *
> + * Copyright (c) 2017 Linaro Limited
> + * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> + */
> +
> +#include "sha256.h"
> +
> +void purgatory(void)
> +{
> + int ret;
> +
> + ret = verify_sha256_digest();
> + if (ret) {
> + /* loop forever */
> + for (;;)
> + ;
> + }
> +}
Surely we can do something slightly better than a busy loop? e.g.
something like the __no_granule_support loop in head.s?
> diff --git a/arch/arm64/purgatory/sha256-core.S b/arch/arm64/purgatory/sha256-core.S
> new file mode 100644
> index 000000000000..24f5ce25b61e
> --- /dev/null
> +++ b/arch/arm64/purgatory/sha256-core.S
> @@ -0,0 +1 @@
> +#include "../crypto/sha256-core.S_shipped"
> diff --git a/arch/arm64/purgatory/sha256.c b/arch/arm64/purgatory/sha256.c
> new file mode 100644
> index 000000000000..5d20d81767e3
> --- /dev/null
> +++ b/arch/arm64/purgatory/sha256.c
> @@ -0,0 +1,79 @@
> +#include <linux/kexec.h>
> +#include <linux/purgatory.h>
> +#include <linux/types.h>
> +
> +/*
> + * Under KASAN, those are defined as un-instrumented version, __memxxx()
> + */
> +#undef memcmp
> +#undef memcpy
> +#undef memset
This doesn't look like the right place for this undeffery; it looks
rather fragile.
> +
> +#include "string.h"
> +#include <crypto/hash.h>
> +#include <crypto/sha.h>
> +#include <crypto/sha256_base.h>
> +
> +u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE] __section(.kexec-purgatory);
> +struct kexec_sha_region purgatory_sha_regions[KEXEC_SEGMENT_MAX]
> + __section(.kexec-purgatory);
> +
> +asmlinkage void sha256_block_data_order(u32 *digest, const void *data,
> + unsigned int num_blks);
> +
> +static int sha256_init(struct shash_desc *desc)
> +{
> + return sha256_base_init(desc);
> +}
> +
> +static int sha256_update(struct shash_desc *desc, const u8 *data,
> + unsigned int len)
> +{
> + return sha256_base_do_update(desc, data, len,
> + (sha256_block_fn *)sha256_block_data_order);
> +}
> +
> +static int __sha256_base_finish(struct shash_desc *desc, u8 *out)
> +{
> + /* we can't do crypto_shash_digestsize(desc->tfm) */
> + unsigned int digest_size = 32;
> + struct sha256_state *sctx = shash_desc_ctx(desc);
> + __be32 *digest = (__be32 *)out;
> + int i;
> +
> + for (i = 0; digest_size > 0; i++, digest_size -= sizeof(__be32))
> + put_unaligned_be32(sctx->state[i], digest++);
> +
> + *sctx = (struct sha256_state){};
> + return 0;
> +}
> +
> +static int sha256_final(struct shash_desc *desc, u8 *out)
> +{
> + sha256_base_do_finalize(desc,
> + (sha256_block_fn *)sha256_block_data_order);
> +
> + return __sha256_base_finish(desc, out);
> +}
> +
> +int verify_sha256_digest(void)
> +{
> + char __sha256_desc[sizeof(struct shash_desc) +
> + sizeof(struct sha256_state)] CRYPTO_MINALIGN_ATTR;
> + struct shash_desc *desc = (struct shash_desc *)__sha256_desc;
> + struct kexec_sha_region *ptr, *end;
> + u8 digest[SHA256_DIGEST_SIZE];
> +
> + sha256_init(desc);
> +
> + end = purgatory_sha_regions + ARRAY_SIZE(purgatory_sha_regions);
> + for (ptr = purgatory_sha_regions; ptr < end; ptr++)
> + sha256_update(desc, (uint8_t *)(ptr->start), ptr->len);
> +
> + sha256_final(desc, digest);
> +
> + if (memcmp(digest, purgatory_sha256_digest, sizeof(digest)))
> + return 1;
> +
> + return 0;
> +}
> diff --git a/arch/arm64/purgatory/sha256.h b/arch/arm64/purgatory/sha256.h
> new file mode 100644
> index 000000000000..54dc3c33c469
> --- /dev/null
> +++ b/arch/arm64/purgatory/sha256.h
> @@ -0,0 +1 @@
> +extern int verify_sha256_digest(void);
> diff --git a/arch/arm64/purgatory/string.c b/arch/arm64/purgatory/string.c
> new file mode 100644
> index 000000000000..33233a210a65
> --- /dev/null
> +++ b/arch/arm64/purgatory/string.c
> @@ -0,0 +1,32 @@
> +#include <linux/types.h>
> +
> +void *memcpy(void *dst, const void *src, size_t len)
> +{
> + int i;
> +
> + for (i = 0; i < len; i++)
> + ((u8 *)dst)[i] = ((u8 *)src)[i];
> +
> + return NULL;
> +}
> +
> +void *memset(void *dst, int c, size_t len)
> +{
> + int i;
> +
> + for (i = 0; i < len; i++)
> + ((u8 *)dst)[i] = (u8)c;
> +
> + return NULL;
> +}
> +
> +int memcmp(const void *src, const void *dst, size_t len)
> +{
> + int i;
> +
> + for (i = 0; i < len; i++)
> + if (*(char *)src != *(char *)dst)
> + return 1;
> +
> + return 0;
> +}
How is the compiler prevented from "optimising" these into calls to
themselves?
I suspect these will need to be written in asm.
Thanks,
Mark.
[toc] | [prev] | [next] | [standalone]
| From | AKASHI Takahiro <takahiro.akashi@linaro.org> |
|---|---|
| Date | 2017-08-25 03:30 +0200 |
| Subject | Re: [PATCH 09/14] arm64: kexec_file: add sha256 digest check in purgatory |
| Message-ID | <uibBD-5Ur-1@gated-at.bofh.it> |
| In reply to | #1719447 |
On Thu, Aug 24, 2017 at 06:04:40PM +0100, Mark Rutland wrote:
> On Thu, Aug 24, 2017 at 05:18:06PM +0900, AKASHI Takahiro wrote:
> > Most of sha256 code is based on crypto/sha256-glue.c, particularly using
> > non-neon version.
> >
> > Please note that we won't be able to re-use lib/mem*.S for purgatory
> > because unaligned memory access is not allowed in purgatory where mmu
> > is turned off.
> >
> > Since purgatory is not linked with the other part of kernel, care must be
> > taken of selecting an appropriate set of compiler options in order to
> > prevent undefined symbol references from being generated.
>
> What is the point in performing this check in the purgatory code, when
> this will presumably have been checked when the image is loaded?
Well, this is what x86 does :)
On powerpc, meanwhile, they don't have this check.
Maybe to avoid booting corrupted kernel after loading?
(loaded data are now protected by making them unmapped, though.)
> [...]
>
> > diff --git a/arch/arm64/purgatory/entry.S b/arch/arm64/purgatory/entry.S
> > index bc4e6b3bf8a1..74d028b838bd 100644
> > --- a/arch/arm64/purgatory/entry.S
> > +++ b/arch/arm64/purgatory/entry.S
> > @@ -6,6 +6,11 @@
> > .text
> >
> > ENTRY(purgatory_start)
> > + adr x19, .Lstack
> > + mov sp, x19
> > +
> > + bl purgatory
> > +
> > /* Start new image. */
> > ldr x17, arm64_kernel_entry
> > ldr x0, arm64_dtb_addr
> > @@ -15,6 +20,14 @@ ENTRY(purgatory_start)
> > br x17
> > END(purgatory_start)
> >
> > +.ltorg
> > +
> > +.align 4
> > + .rept 256
> > + .quad 0
> > + .endr
> > +.Lstack:
> > +
> > .data
>
> Why is the stack in .text?
to call verify_sha256_digest() from asm
> Does this need to be zeroed?
No :)
> If it does, why not something like:
>
> .fill PURGATORY_STACK_SIZE 1, 0
>
> >
> > .align 3
> > diff --git a/arch/arm64/purgatory/purgatory.c b/arch/arm64/purgatory/purgatory.c
> > new file mode 100644
> > index 000000000000..7fcbefa786bc
> > --- /dev/null
> > +++ b/arch/arm64/purgatory/purgatory.c
> > @@ -0,0 +1,20 @@
> > +/*
> > + * purgatory: Runs between two kernels
> > + *
> > + * Copyright (c) 2017 Linaro Limited
> > + * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > + */
> > +
> > +#include "sha256.h"
> > +
> > +void purgatory(void)
> > +{
> > + int ret;
> > +
> > + ret = verify_sha256_digest();
> > + if (ret) {
> > + /* loop forever */
> > + for (;;)
> > + ;
> > + }
> > +}
>
> Surely we can do something slightly better than a busy loop? e.g.
> something like the __no_granule_support loop in head.s?
Okey.
> > diff --git a/arch/arm64/purgatory/sha256-core.S b/arch/arm64/purgatory/sha256-core.S
> > new file mode 100644
> > index 000000000000..24f5ce25b61e
> > --- /dev/null
> > +++ b/arch/arm64/purgatory/sha256-core.S
> > @@ -0,0 +1 @@
> > +#include "../crypto/sha256-core.S_shipped"
> > diff --git a/arch/arm64/purgatory/sha256.c b/arch/arm64/purgatory/sha256.c
> > new file mode 100644
> > index 000000000000..5d20d81767e3
> > --- /dev/null
> > +++ b/arch/arm64/purgatory/sha256.c
> > @@ -0,0 +1,79 @@
> > +#include <linux/kexec.h>
> > +#include <linux/purgatory.h>
> > +#include <linux/types.h>
> > +
> > +/*
> > + * Under KASAN, those are defined as un-instrumented version, __memxxx()
> > + */
> > +#undef memcmp
> > +#undef memcpy
> > +#undef memset
>
> This doesn't look like the right place for this undeffery; it looks
> rather fragile.
Yeah, I agree, but if not there, __memxxx() are used.
> > diff --git a/arch/arm64/purgatory/string.c b/arch/arm64/purgatory/string.c
> > new file mode 100644
> > index 000000000000..33233a210a65
> > --- /dev/null
> > +++ b/arch/arm64/purgatory/string.c
> > @@ -0,0 +1,32 @@
> > +#include <linux/types.h>
> > +
> > +void *memcpy(void *dst, const void *src, size_t len)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < len; i++)
> > + ((u8 *)dst)[i] = ((u8 *)src)[i];
> > +
> > + return NULL;
> > +}
> > +
> > +void *memset(void *dst, int c, size_t len)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < len; i++)
> > + ((u8 *)dst)[i] = (u8)c;
> > +
> > + return NULL;
> > +}
> > +
> > +int memcmp(const void *src, const void *dst, size_t len)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < len; i++)
> > + if (*(char *)src != *(char *)dst)
> > + return 1;
> > +
> > + return 0;
> > +}
>
> How is the compiler prevented from "optimising" these into calls to
> themselves?
I don't get what you mean by "calls to themselves."
Thanks,
-Takahiro AKASHI
> I suspect these will need to be written in asm.
>
> Thanks,
> Mark.
[toc] | [prev] | [next] | [standalone]
| From | Mark Rutland <mark.rutland@arm.com> |
|---|---|
| Date | 2017-08-25 12:50 +0200 |
| Subject | Re: [PATCH 09/14] arm64: kexec_file: add sha256 digest check in purgatory |
| Message-ID | <uiklA-2V8-15@gated-at.bofh.it> |
| In reply to | #1719698 |
On Fri, Aug 25, 2017 at 10:21:06AM +0900, AKASHI Takahiro wrote:
> On Thu, Aug 24, 2017 at 06:04:40PM +0100, Mark Rutland wrote:
> > On Thu, Aug 24, 2017 at 05:18:06PM +0900, AKASHI Takahiro wrote:
> > > Most of sha256 code is based on crypto/sha256-glue.c, particularly using
> > > non-neon version.
> > >
> > > Please note that we won't be able to re-use lib/mem*.S for purgatory
> > > because unaligned memory access is not allowed in purgatory where mmu
> > > is turned off.
> > >
> > > Since purgatory is not linked with the other part of kernel, care must be
> > > taken of selecting an appropriate set of compiler options in order to
> > > prevent undefined symbol references from being generated.
> >
> > What is the point in performing this check in the purgatory code, when
> > this will presumably have been checked when the image is loaded?
>
> Well, this is what x86 does :)
> On powerpc, meanwhile, they don't have this check.
>
> Maybe to avoid booting corrupted kernel after loading?
> (loaded data are now protected by making them unmapped, though.)
I'd really prefer to avoid this, since it seems to be what necessitates
all the complexity for executing C code (linking and all), and it's
going to be very slow to execute with the MMU off.
If you can deliberately corrupt the next kernel, you could also have
corrupted the purgatory to skip the check.
Unless we have a strong reason to want the hash check, I think it should
be dropped.
> > > diff --git a/arch/arm64/purgatory/entry.S b/arch/arm64/purgatory/entry.S
> > > index bc4e6b3bf8a1..74d028b838bd 100644
> > > --- a/arch/arm64/purgatory/entry.S
> > > +++ b/arch/arm64/purgatory/entry.S
> > > @@ -6,6 +6,11 @@
> > > .text
> > >
> > > ENTRY(purgatory_start)
> > > + adr x19, .Lstack
> > > + mov sp, x19
> > > +
> > > + bl purgatory
> > > +
> > > /* Start new image. */
> > > ldr x17, arm64_kernel_entry
> > > ldr x0, arm64_dtb_addr
> > > @@ -15,6 +20,14 @@ ENTRY(purgatory_start)
> > > br x17
> > > END(purgatory_start)
> > >
> > > +.ltorg
> > > +
> > > +.align 4
> > > + .rept 256
> > > + .quad 0
> > > + .endr
> > > +.Lstack:
> > > +
> > > .data
> >
> > Why is the stack in .text?
>
> to call verify_sha256_digest() from asm
Won't that also work if the stack is in .data? or .bss?
... or is there a particular need for it to be in .text?
> > Does this need to be zeroed?
>
> No :)
Ok, so we can probably do:
.data
.align 4
. += PURGATORY_STACK_SIZE
.Lstack_ptr:
... assuming we need to run C code.
[...]
> > > diff --git a/arch/arm64/purgatory/sha256.c b/arch/arm64/purgatory/sha256.c
> > > new file mode 100644
> > > index 000000000000..5d20d81767e3
> > > --- /dev/null
> > > +++ b/arch/arm64/purgatory/sha256.c
> > > @@ -0,0 +1,79 @@
> > > +#include <linux/kexec.h>
> > > +#include <linux/purgatory.h>
> > > +#include <linux/types.h>
> > > +
> > > +/*
> > > + * Under KASAN, those are defined as un-instrumented version, __memxxx()
> > > + */
> > > +#undef memcmp
> > > +#undef memcpy
> > > +#undef memset
> >
> > This doesn't look like the right place for this undeffery; it looks
> > rather fragile.
>
> Yeah, I agree, but if not there, __memxxx() are used.
Ok, but we'll have to add this to every C file used in the purgatory
code, or at the start of any header that uses a memxxx() function, or it
might still be overridden to use __memxxx(), before the undef takes
effect.
Can we define __memxxx() instead?
[...]
> > > +void *memcpy(void *dst, const void *src, size_t len)
> > > +{
> > > + int i;
> > > +
> > > + for (i = 0; i < len; i++)
> > > + ((u8 *)dst)[i] = ((u8 *)src)[i];
> > > +
> > > + return NULL;
> > > +}
> > > +
> > > +void *memset(void *dst, int c, size_t len)
> > > +{
> > > + int i;
> > > +
> > > + for (i = 0; i < len; i++)
> > > + ((u8 *)dst)[i] = (u8)c;
> > > +
> > > + return NULL;
> > > +}
> > > +
> > > +int memcmp(const void *src, const void *dst, size_t len)
> > > +{
> > > + int i;
> > > +
> > > + for (i = 0; i < len; i++)
> > > + if (*(char *)src != *(char *)dst)
> > > + return 1;
> > > +
> > > + return 0;
> > > +}
> >
> > How is the compiler prevented from "optimising" these into calls to
> > themselves?
>
> I don't get what you mean by "calls to themselves."
There are compiler optimizations that recognise sequences like:
for (i = 0; i < len; i++)
dst[i] = src[i];
... and turn those into:
memcpy(dst, src, len);
... these have been known to "optimize" memcpy implementations into
calls to themselves. Likewise for other string operations.
One way we avoid that today is by writing our memcpy in assembly.
Do we have a guarnatee that this will not happen here? e.g. do we pass
some compiler flag that prevents this?
Thanks,
Mark.
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web