Re: [PATCH 14/14] arm64: kexec_file: add vmlinux format support

From: Mark Rutland
Date: Thu Aug 24 2017 - 13:32:11 EST


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@xxxxxxxxxx>
> + *
> + * 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.