From patchwork Sun Jun 7 23:33:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prakhar Srivastava X-Patchwork-Id: 11592387 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 63F6B17CA for ; Sun, 7 Jun 2020 23:33:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4B3E320810 for ; Sun, 7 Jun 2020 23:33:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="s9OgKPoz" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728007AbgFGXdj (ORCPT ); Sun, 7 Jun 2020 19:33:39 -0400 Received: from linux.microsoft.com ([13.77.154.182]:34074 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727791AbgFGXdg (ORCPT ); Sun, 7 Jun 2020 19:33:36 -0400 Received: from prsriva-linux.hsd1.wa.comcast.net (c-24-19-135-168.hsd1.wa.comcast.net [24.19.135.168]) by linux.microsoft.com (Postfix) with ESMTPSA id ACADC20B7185; Sun, 7 Jun 2020 16:33:32 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com ACADC20B7185 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1591572813; bh=EpddQoxQfAk3s2Oy6M0XPpzUI9QJInmVAojNAsXL/kc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=s9OgKPozlv7JNwI22KFiZY7fDGrkocxyugTj9/JxOzhKjcOffYDZS0IQh9xfbTYhM conzU4SIsS0BoRKO300iL41X+k851ZAYbt9CjWwOs45KvE5n3H7mK1YN6VpYRwFsyX VIDP7LcwVhmRgRIfBa9MXQmDCazJEY2Fd9pdWZls= From: Prakhar Srivastava To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org Cc: catalin.marinas@arm.com, will@kernel.org, mpe@ellerman.id.au, benh@kernel.crashing.org, paulus@samba.org, robh+dt@kernel.org, frowand.list@gmail.com, zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, jmorris@namei.org, serge@hallyn.com, pasha.tatashin@soleen.com, allison@lohutok.net, kstewart@linuxfoundation.org, takahiro.akashi@linaro.org, tglx@linutronix.de, vincenzo.frascino@arm.com, mark.rutland@arm.com, masahiroy@kernel.org, james.morse@arm.com, bhsharma@redhat.com, mbrugger@suse.com, hsinyi@chromium.org, tao.li@vivo.com, christophe.leroy@c-s.fr, gregkh@linuxfoundation.org, nramas@linux.microsoft.com, prsriva@linux.microsoft.com, tusharsu@linux.microsoft.com, balajib@linux.microsoft.com Subject: [v1 PATCH 1/2] Refactoring carrying over IMA measuremnet logs over Kexec. Date: Sun, 7 Jun 2020 16:33:22 -0700 Message-Id: <20200607233323.22375-2-prsriva@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200607233323.22375-1-prsriva@linux.microsoft.com> References: <20200607233323.22375-1-prsriva@linux.microsoft.com> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: This patch moves the non-architecture specific code out of powerpc and adds to security/ima. Update the arm64 and powerpc kexec file load paths to carry the IMA measurement logs. Signed-off-by: Prakhar Srivastava Reported-by: kernel test robot Reported-by: kernel test robot --- arch/arm64/Kconfig | 1 + arch/arm64/include/asm/ima.h | 24 ++++ arch/arm64/include/asm/kexec.h | 3 + arch/arm64/kernel/machine_kexec_file.c | 47 ++++++-- arch/powerpc/include/asm/ima.h | 9 -- arch/powerpc/kexec/ima.c | 117 +------------------ security/integrity/ima/ima_kexec.c | 151 +++++++++++++++++++++++++ 7 files changed, 219 insertions(+), 133 deletions(-) create mode 100644 arch/arm64/include/asm/ima.h diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 5d513f461957..3d544e2e25e6 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1070,6 +1070,7 @@ config KEXEC config KEXEC_FILE bool "kexec file based system call" select KEXEC_CORE + select HAVE_IMA_KEXEC help This is new version of kexec system call. This system call is file based and takes file descriptors as system call argument diff --git a/arch/arm64/include/asm/ima.h b/arch/arm64/include/asm/ima.h new file mode 100644 index 000000000000..8946bae8baa2 --- /dev/null +++ b/arch/arm64/include/asm/ima.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_ARCH_IMA_H +#define _ASM_ARCH_IMA_H + +struct kimage; + +#ifdef CONFIG_IMA_KEXEC +int arch_ima_add_kexec_buffer(struct kimage *image, unsigned long load_addr, + size_t size); + +int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node); +#else +static inline int arch_ima_add_kexec_buffer(struct kimage *image, + unsigned long load_addr, size_t size) +{ + return 0; +} +static inline int setup_ima_buffer(const struct kimage *image, void *fdt, + int chosen_node) +{ + return 0; +} +#endif /* CONFIG_IMA_KEXEC */ +#endif /* _ASM_ARCH_IMA_H */ diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h index d24b527e8c00..7bd60c185ad3 100644 --- a/arch/arm64/include/asm/kexec.h +++ b/arch/arm64/include/asm/kexec.h @@ -100,6 +100,9 @@ struct kimage_arch { void *elf_headers; unsigned long elf_headers_mem; unsigned long elf_headers_sz; + + phys_addr_t ima_buffer_addr; + size_t ima_buffer_size; }; extern const struct kexec_file_ops kexec_image_ops; diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c index b40c3b0def92..1e9007c926db 100644 --- a/arch/arm64/kernel/machine_kexec_file.c +++ b/arch/arm64/kernel/machine_kexec_file.c @@ -24,20 +24,37 @@ #include /* relevant device tree properties */ -#define FDT_PROP_KEXEC_ELFHDR "linux,elfcorehdr" -#define FDT_PROP_MEM_RANGE "linux,usable-memory-range" -#define FDT_PROP_INITRD_START "linux,initrd-start" -#define FDT_PROP_INITRD_END "linux,initrd-end" -#define FDT_PROP_BOOTARGS "bootargs" -#define FDT_PROP_KASLR_SEED "kaslr-seed" -#define FDT_PROP_RNG_SEED "rng-seed" -#define RNG_SEED_SIZE 128 +#define FDT_PROP_KEXEC_ELFHDR "linux,elfcorehdr" +#define FDT_PROP_MEM_RANGE "linux,usable-memory-range" +#define FDT_PROP_INITRD_START "linux,initrd-start" +#define FDT_PROP_INITRD_END "linux,initrd-end" +#define FDT_PROP_BOOTARGS "bootargs" +#define FDT_PROP_KASLR_SEED "kaslr-seed" +#define FDT_PROP_RNG_SEED "rng-seed" +#define FDT_PROP_IMA_KEXEC_BUFFER "linux,ima-kexec-buffer" +#define RNG_SEED_SIZE 128 const struct kexec_file_ops * const kexec_file_loaders[] = { &kexec_image_ops, NULL }; +/** + * arch_ima_add_kexec_buffer - do arch-specific steps to add the IMA buffer + * + * Architectures should use this function to pass on the IMA buffer + * information to the next kernel. + * + * Return: 0 on success, negative errno on error. + */ +int arch_ima_add_kexec_buffer(struct kimage *image, unsigned long load_addr, + size_t size) +{ + image->arch.ima_buffer_addr = load_addr; + image->arch.ima_buffer_size = size; + return 0; +} + int arch_kimage_file_post_load_cleanup(struct kimage *image) { vfree(image->arch.dtb); @@ -66,6 +83,9 @@ static int setup_dtb(struct kimage *image, if (ret && ret != -FDT_ERR_NOTFOUND) goto out; ret = fdt_delprop(dtb, off, FDT_PROP_MEM_RANGE); + if (ret && ret != -FDT_ERR_NOTFOUND) + goto out; + ret = fdt_delprop(dtb, off, FDT_PROP_IMA_KEXEC_BUFFER); if (ret && ret != -FDT_ERR_NOTFOUND) goto out; @@ -119,6 +139,17 @@ static int setup_dtb(struct kimage *image, goto out; } + if (image->arch.ima_buffer_size > 0) { + + ret = fdt_appendprop_addrrange(dtb, 0, off, + FDT_PROP_IMA_KEXEC_BUFFER, + image->arch.ima_buffer_addr, + image->arch.ima_buffer_size); + if (ret) + return (ret == -FDT_ERR_NOSPACE ? -ENOMEM : -EINVAL); + + } + /* add kaslr-seed */ ret = fdt_delprop(dtb, off, FDT_PROP_KASLR_SEED); if (ret == -FDT_ERR_NOTFOUND) diff --git a/arch/powerpc/include/asm/ima.h b/arch/powerpc/include/asm/ima.h index ead488cf3981..80b83881fa03 100644 --- a/arch/powerpc/include/asm/ima.h +++ b/arch/powerpc/include/asm/ima.h @@ -4,15 +4,6 @@ struct kimage; -int ima_get_kexec_buffer(void **addr, size_t *size); -int ima_free_kexec_buffer(void); - -#ifdef CONFIG_IMA -void remove_ima_buffer(void *fdt, int chosen_node); -#else -static inline void remove_ima_buffer(void *fdt, int chosen_node) {} -#endif - #ifdef CONFIG_IMA_KEXEC int arch_ima_add_kexec_buffer(struct kimage *image, unsigned long load_addr, size_t size); diff --git a/arch/powerpc/kexec/ima.c b/arch/powerpc/kexec/ima.c index 720e50e490b6..537e4f82a050 100644 --- a/arch/powerpc/kexec/ima.c +++ b/arch/powerpc/kexec/ima.c @@ -12,121 +12,6 @@ #include #include -static int get_addr_size_cells(int *addr_cells, int *size_cells) -{ - struct device_node *root; - - root = of_find_node_by_path("/"); - if (!root) - return -EINVAL; - - *addr_cells = of_n_addr_cells(root); - *size_cells = of_n_size_cells(root); - - of_node_put(root); - - return 0; -} - -static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr, - size_t *size) -{ - int ret, addr_cells, size_cells; - - ret = get_addr_size_cells(&addr_cells, &size_cells); - if (ret) - return ret; - - if (len < 4 * (addr_cells + size_cells)) - return -ENOENT; - - *addr = of_read_number(prop, addr_cells); - *size = of_read_number(prop + 4 * addr_cells, size_cells); - - return 0; -} - -/** - * ima_get_kexec_buffer - get IMA buffer from the previous kernel - * @addr: On successful return, set to point to the buffer contents. - * @size: On successful return, set to the buffer size. - * - * Return: 0 on success, negative errno on error. - */ -int ima_get_kexec_buffer(void **addr, size_t *size) -{ - int ret, len; - unsigned long tmp_addr; - size_t tmp_size; - const void *prop; - - prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len); - if (!prop) - return -ENOENT; - - ret = do_get_kexec_buffer(prop, len, &tmp_addr, &tmp_size); - if (ret) - return ret; - - *addr = __va(tmp_addr); - *size = tmp_size; - - return 0; -} - -/** - * ima_free_kexec_buffer - free memory used by the IMA buffer - */ -int ima_free_kexec_buffer(void) -{ - int ret; - unsigned long addr; - size_t size; - struct property *prop; - - prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL); - if (!prop) - return -ENOENT; - - ret = do_get_kexec_buffer(prop->value, prop->length, &addr, &size); - if (ret) - return ret; - - ret = of_remove_property(of_chosen, prop); - if (ret) - return ret; - - return memblock_free(addr, size); - -} - -/** - * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt - * - * The IMA measurement buffer is of no use to a subsequent kernel, so we always - * remove it from the device tree. - */ -void remove_ima_buffer(void *fdt, int chosen_node) -{ - int ret, len; - unsigned long addr; - size_t size; - const void *prop; - - prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len); - if (!prop) - return; - - ret = do_get_kexec_buffer(prop, len, &addr, &size); - fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer"); - if (ret) - return; - - ret = delete_fdt_mem_rsv(fdt, addr, size); - if (!ret) - pr_debug("Removed old IMA buffer reservation.\n"); -} - #ifdef CONFIG_IMA_KEXEC /** * arch_ima_add_kexec_buffer - do arch-specific steps to add the IMA buffer @@ -179,7 +64,7 @@ int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node) int ret, addr_cells, size_cells, entry_size; u8 value[16]; - remove_ima_buffer(fdt, chosen_node); +// remove_ima_buffer(fdt, chosen_node); if (!image->arch.ima_buffer_size) return 0; diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 121de3e04af2..36887ed4ff82 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -10,8 +10,159 @@ #include #include #include +#include +#include +#include #include "ima.h" +static int get_addr_size_cells(int *addr_cells, int *size_cells) +{ + struct device_node *root; + + root = of_find_node_by_path("/"); + if (!root) + return -EINVAL; + + *addr_cells = of_n_addr_cells(root); + *size_cells = of_n_size_cells(root); + + of_node_put(root); + + return 0; +} + +static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr, + size_t *size) +{ + int ret, addr_cells, size_cells; + + ret = get_addr_size_cells(&addr_cells, &size_cells); + if (ret) + return ret; + + if (len < 4 * (addr_cells + size_cells)) + return -ENOENT; + + *addr = of_read_number(prop, addr_cells); + *size = of_read_number(prop + 4 * addr_cells, size_cells); + + return 0; +} + +/** + * ima_get_kexec_buffer - get IMA buffer from the previous kernel + * @addr: On successful return, set to point to the buffer contents. + * @size: On successful return, set to the buffer size. + * + * Return: 0 on success, negative errno on error. + */ +int ima_get_kexec_buffer(void **addr, size_t *size) +{ + int ret, len; + unsigned long tmp_addr; + size_t tmp_size; + const void *prop; + + prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len); + if (!prop) + return -ENOENT; + + ret = do_get_kexec_buffer(prop, len, &tmp_addr, &tmp_size); + if (ret) + return ret; + + *addr = __va(tmp_addr); + *size = tmp_size; + + return 0; +} + +/** + * delete_fdt_mem_rsv - delete memory reservation with given address and size + * + * Return: 0 on success, or negative errno on error. + */ +int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size) +{ + int i, ret, num_rsvs = fdt_num_mem_rsv(fdt); + + for (i = 0; i < num_rsvs; i++) { + uint64_t rsv_start, rsv_size; + + ret = fdt_get_mem_rsv(fdt, i, &rsv_start, &rsv_size); + if (ret) { + pr_err("Malformed device tree.\n"); + return -EINVAL; + } + + if (rsv_start == start && rsv_size == size) { + ret = fdt_del_mem_rsv(fdt, i); + if (ret) { + pr_err("Error deleting device tree reservation.\n"); + return -EINVAL; + } + + return 0; + } + } + + return -ENOENT; +} + +/** + * ima_free_kexec_buffer - free memory used by the IMA buffer + */ +int ima_free_kexec_buffer(void) +{ + int ret; + unsigned long addr; + size_t size; + struct property *prop; + + prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL); + if (!prop) + return -ENOENT; + + ret = do_get_kexec_buffer(prop->value, prop->length, &addr, &size); + if (ret) + return ret; + + ret = of_remove_property(of_chosen, prop); + if (ret) + return ret; + + return memblock_free(addr, size); + +} + +/** + * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt + * + * The IMA measurement buffer is of no use to a subsequent kernel, so we always + * remove it from the device tree. + */ +void remove_ima_buffer(void *fdt, int chosen_node) +{ + int ret, len; + unsigned long addr; + size_t size; + const void *prop; + + prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len); + if (!prop) + return; + + ret = do_get_kexec_buffer(prop, len, &addr, &size); + fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer"); + if (ret) + return; + + ret = delete_fdt_mem_rsv(fdt, addr, size); + if (!ret) + pr_debug("Removed old IMA buffer reservation.\n"); +} + + #ifdef CONFIG_IMA_KEXEC static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, unsigned long segment_size)