From: Prakhar Srivastava <prsriva@linux.microsoft.com>
To: linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-integrity@vger.kernel.org, kexec@lists.infradead.org
Cc: mark.rutland@arm.com, jean-philippe@linaro.org, arnd@arndb.de,
takahiro.akashi@linaro.org, sboyd@kernel.org,
catalin.marinas@arm.com, zohar@linux.ibm.com,
yamada.masahiro@socionext.com, kristina.martsenko@arm.org,
duwe@lst.de, bauerman@linux.ibm.com, james.morse@arm.org,
tglx@linutronix.de, allison@lohutok.net
Subject: [PATCH v2 1/2] Add support for arm64 to carry ima measurement log in kexec_file_load
Date: Mon, 7 Oct 2019 11:59:42 -0700 [thread overview]
Message-ID: <20191007185943.1828-2-prsriva@linux.microsoft.com> (raw)
In-Reply-To: <20191007185943.1828-1-prsriva@linux.microsoft.com>
During kexec_file_load, carrying forward the ima measurement log allows
a verifying party to get the entire runtime event log since the last
full reboot since that is when PCRs were last reset.
Signed-off-by: Prakhar Srivastava <prsriva@linux.microsoft.com>
---
arch/Kconfig | 6 +-
arch/arm64/include/asm/ima.h | 24 +++
arch/arm64/include/asm/kexec.h | 5 +
arch/arm64/kernel/Makefile | 3 +-
arch/arm64/kernel/ima_kexec.c | 78 ++++++++++
arch/arm64/kernel/machine_kexec_file.c | 6 +
drivers/of/Kconfig | 6 +
drivers/of/Makefile | 1 +
drivers/of/of_ima.c | 204 +++++++++++++++++++++++++
include/linux/of.h | 31 ++++
10 files changed, 362 insertions(+), 2 deletions(-)
create mode 100644 arch/arm64/include/asm/ima.h
create mode 100644 arch/arm64/kernel/ima_kexec.c
create mode 100644 drivers/of/of_ima.c
diff --git a/arch/Kconfig b/arch/Kconfig
index a7b57dd42c26..d53e1596c5b1 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -19,7 +19,11 @@ config KEXEC_CORE
bool
config HAVE_IMA_KEXEC
- bool
+ bool "Carry over IMA measurement log during kexec_file_load() syscall"
+ depends on KEXEC_FILE
+ help
+ Select this option to carry over IMA measurement log during
+ kexec_file_load.
config HOTPLUG_SMT
bool
diff --git a/arch/arm64/include/asm/ima.h b/arch/arm64/include/asm/ima.h
new file mode 100644
index 000000000000..287dbcefd15e
--- /dev/null
+++ b/arch/arm64/include/asm/ima.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ARM64_IMA_H
+#define _ASM_ARM64_IMA_H
+
+struct kimage;
+
+int ima_get_kexec_buffer(void **addr, size_t *size);
+int ima_free_kexec_buffer(void);
+void remove_ima_buffer(void *fdt, int chosen_node);
+
+#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 setup_ima_buffer(const struct kimage *image, void *fdt,
+ int chosen_node)
+{
+ remove_ima_buffer(fdt, chosen_node);
+ return 0;
+}
+#endif /* CONFIG_IMA_KEXEC */
+#endif /* _ASM_ARM64_IMA_H */
diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
index 12a561a54128..e8d2412066e7 100644
--- a/arch/arm64/include/asm/kexec.h
+++ b/arch/arm64/include/asm/kexec.h
@@ -96,6 +96,11 @@ static inline void crash_post_resume(void) {}
struct kimage_arch {
void *dtb;
unsigned long dtb_mem;
+
+#ifdef CONFIG_IMA_KEXEC
+ phys_addr_t ima_buffer_addr;
+ size_t ima_buffer_size;
+#endif
};
extern const struct kexec_file_ops kexec_image_ops;
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 478491f07b4f..580238f2e9a7 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -55,7 +55,8 @@ obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o
obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o relocate_kernel.o \
cpu-reset.o
-obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o kexec_image.o
+obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o kexec_image.o \
+ ima_kexec.o
obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o
arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
diff --git a/arch/arm64/kernel/ima_kexec.c b/arch/arm64/kernel/ima_kexec.c
new file mode 100644
index 000000000000..c2450aaa42c8
--- /dev/null
+++ b/arch/arm64/kernel/ima_kexec.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Authors:
+ * Prakhar Srivastava <prsriva@linux.microsoft.com>
+ */
+
+#include <linux/kexec.h>
+#include <linux/of.h>
+
+/**
+ * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
+ * The IMA measurement buffer once read needs to be freed.
+ */
+void remove_ima_buffer(void *fdt, int chosen_node)
+{
+ fdt_remove_ima_buffer(fdt, chosen_node);
+}
+
+/**
+ * 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)
+{
+ return of_get_ima_buffer(addr, size);
+}
+
+/**
+ * ima_free_kexec_buffer - free memory used by the IMA buffer
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int ima_free_kexec_buffer(void)
+{
+ return of_remove_ima_buffer();
+}
+
+#ifdef CONFIG_IMA_KEXEC
+/**
+ * arch_ima_add_kexec_buffer - do arch-specific steps to add the IMA
+ * measurement log.
+ * @image: - pointer to the kimage, to store the address and size of the
+ * IMA measurement log.
+ * @load_addr: - the address where the IMA measurement log is stored.
+ * @size - size of the IMA measurement log.
+ *
+ * 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;
+}
+
+/**
+ * setup_ima_buffer - update the fdt to contain the ima mesasurement log
+ * @image: - pointer to the kimage, containing the address and size of
+ * the IMA measurement log.
+ * @fdt: - pointer to the fdt.
+ * @chosen_node: - node under which property is to be defined.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node)
+{
+ return fdt_setup_ima_buffer(image->arch.ima_buffer_addr,
+ image->arch.ima_buffer_size,
+ fdt, chosen_node);
+
+}
+#endif /* CONFIG_IMA_KEXEC */
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index 58871333737a..86d57198d739 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -21,6 +21,7 @@
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <asm/byteorder.h>
+#include <asm/ima.h>
/* relevant device tree properties */
#define FDT_PROP_INITRD_START "linux,initrd-start"
@@ -85,6 +86,11 @@ static int setup_dtb(struct kimage *image,
goto out;
}
+ /* add ima measuremnet log buffer */
+ ret = setup_ima_buffer(image, dtb, off);
+ if (ret < 0)
+ goto out;
+
/* add kaslr-seed */
ret = fdt_delprop(dtb, off, FDT_PROP_KASLR_SEED);
if (ret == -FDT_ERR_NOTFOUND)
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 37c2ccbefecd..167c6ecb64aa 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -103,4 +103,10 @@ config OF_OVERLAY
config OF_NUMA
bool
+config OF_IMA
+ def_bool y
+ help
+ IMA related wrapper functions to add/remove ima measurement logs during
+ kexec_file_load call.
+
endif # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 663a4af0cccd..b4caf083df4e 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -14,5 +14,6 @@ obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
obj-$(CONFIG_OF_RESOLVE) += resolver.o
obj-$(CONFIG_OF_OVERLAY) += overlay.o
obj-$(CONFIG_OF_NUMA) += of_numa.o
+obj-$(CONFIG_OF_IMA) += of_ima.o
obj-$(CONFIG_OF_UNITTEST) += unittest-data/
diff --git a/drivers/of/of_ima.c b/drivers/of/of_ima.c
new file mode 100644
index 000000000000..cfc3cb4522b0
--- /dev/null
+++ b/drivers/of/of_ima.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ */
+
+#include <linux/slab.h>
+#include <linux/kexec.h>
+#include <linux/of.h>
+#include <linux/memblock.h>
+#include <linux/libfdt.h>
+
+/**
+ * delete_fdt_mem_rsv - delete memory reservation with given address and size
+ * @fdt - pointer to the fdt.
+ * @start - start address of the memory.
+ * @size - number of cells to be deletd.
+ *
+ * Return: 0 on success, or negative errno on error.
+ */
+int fdt_delete_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 < 0) {
+ pr_err("Malformed device tree\n");
+ return ret;
+ }
+
+ if (rsv_start == start && rsv_size == size) {
+ ret = fdt_del_mem_rsv(fdt, i);
+ if (ret < 0) {
+ pr_err("Error deleting device tree reservation\n");
+ return ret;
+ }
+
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * of_get_ima_buffer_properties - get the properties for ima buffer
+ * @ima_buf_start - start of the ima buffer
+ * @ima_buf_end - end of the ima buffer
+ * If any one of the properties is not found. The device tree
+ * is malformed or something went wrong.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int of_get_ima_buffer_properties(void **ima_buf_start, void **ima_buf_end)
+{
+ struct property *pproperty;
+
+ pproperty = of_find_property(of_chosen, "linux,ima-kexec-buffer",
+ NULL);
+ *ima_buf_start = pproperty ? pproperty->value : NULL;
+
+ pproperty = of_find_property(of_chosen, "linux,ima-kexec-buffer-end",
+ NULL);
+ *ima_buf_end = pproperty ? pproperty->value : NULL;
+
+ if (!*ima_buf_start || !*ima_buf_end)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * of_remove_ima_buffer - free memory used by the IMA buffer
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int of_remove_ima_buffer(void)
+{
+ int ret;
+ void *ima_buf_start, *ima_buf_end;
+ uint64_t buf_start, buf_end;
+
+ ret = of_get_ima_buffer_properties(&ima_buf_start, &ima_buf_end);
+ if (ret < 0)
+ return ret;
+
+ buf_start = fdt64_to_cpu(*((const fdt64_t *) ima_buf_start));
+ buf_end = fdt64_to_cpu(*((const fdt64_t *) ima_buf_end));
+
+ ret = of_remove_property(of_chosen, ima_buf_start);
+ if (ret < 0)
+ return ret;
+
+ ret = of_remove_property(of_chosen, ima_buf_end);
+ if (ret < 0)
+ return ret;
+
+ return memblock_free(buf_start, buf_end - buf_start);
+}
+
+/**
+ * of_get_ima_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 of_get_ima_buffer(void **addr, size_t *size)
+{
+ int ret;
+ void *ima_buf_start, *ima_buf_end;
+ uint64_t buf_start, buf_end;
+
+ ret = of_get_ima_buffer_properties(&ima_buf_start, &ima_buf_end);
+ if (ret < 0)
+ return ret;
+
+ buf_start = fdt64_to_cpu(*((const fdt64_t *) ima_buf_start));
+ buf_end = fdt64_to_cpu(*((const fdt64_t *) ima_buf_end));
+
+ *addr = __va(buf_start);
+ *size = buf_end - buf_start;
+
+ return 0;
+}
+
+/**
+ * fdt_remove_ima_buffer - remove the IMA buffer property and reservation
+ * @fdt - pointer the fdt.
+ * @chosen_node - node under which property can be found.
+ *
+ * The IMA measurement buffer is either read by now and freeed or a kexec call
+ * needs to replace the ima measurement buffer, clear the property and memory
+ * reservation.
+ */
+void fdt_remove_ima_buffer(void *fdt, int chosen_node)
+{
+ int ret, len;
+ const void *prop;
+ uint64_t tmp_start, tmp_end;
+
+ prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len);
+ if (prop) {
+ tmp_start = fdt64_to_cpu(*((const fdt64_t *) prop));
+
+ prop = fdt_getprop(fdt, chosen_node,
+ "linux,ima-kexec-buffer-end", &len);
+ if (!prop)
+ return;
+
+ tmp_end = fdt64_to_cpu(*((const fdt64_t *) prop));
+
+ ret = fdt_delete_mem_rsv(fdt, tmp_start, tmp_end - tmp_start);
+
+ if (ret == 0)
+ pr_debug("Removed old IMA buffer reservation.\n");
+ else if (ret != -ENOENT)
+ return;
+
+ fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer");
+ fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer-end");
+ }
+}
+
+/**
+ * fdt_setup_ima_buffer - update the fdt to contain the ima mesasurement log
+ * @image: - pointer to the kimage, containing the address and size of
+ * the IMA measurement log.
+ * @fdt: - pointer to the fdt.
+ * @chosen_node: - node under which property is to be defined.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int fdt_setup_ima_buffer(const phys_addr_t ima_buffer_addr,
+ const size_t ima_buffer_size,
+ void *fdt, int chosen_node)
+{
+ int ret;
+
+ fdt_remove_ima_buffer(fdt, chosen_node);
+
+ if (!ima_buffer_addr)
+ return 0;
+
+ ret = fdt_setprop_u64(fdt, chosen_node, "linux,ima-kexec-buffer",
+ ima_buffer_addr);
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_setprop_u64(fdt, chosen_node, "linux,ima-kexec-buffer-end",
+ ima_buffer_addr +
+ ima_buffer_size);
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_add_mem_rsv(fdt, ima_buffer_addr,
+ ima_buffer_size);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
diff --git a/include/linux/of.h b/include/linux/of.h
index 844f89e1b039..7831c2972178 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -1477,4 +1477,35 @@ static inline int of_overlay_notifier_unregister(struct notifier_block *nb)
#endif
+#ifdef CONFIG_OF_IMA
+int of_remove_ima_buffer(void);
+int of_get_ima_buffer(void **addr, size_t *size);
+void fdt_remove_ima_buffer(void *fdt, int chosen_node);
+int fdt_setup_ima_buffer(const phys_addr_t ima_buffer_addr,
+ const size_t ima_buffer_size,
+ void *fdt, int chosen_node);
+#else
+static inline int of_remove_ima_buffer(void)
+{
+ return -ENOTSUPP;
+};
+
+static inline int of_get_ima_buffer(void **addr, size_t *size)
+{
+ return -ENOTSUPP;
+};
+
+static inline void fdt_remove_ima_buffer(void *fdt, int chosen_node)
+{
+ return -ENOTSUPP;
+};
+
+static inline int fdt_setup_ima_buffer(const phys_addr_t ima_buffer_addr,
+ const size_t ima_buffer_size, void *fdt, int chosen_node)
+{
+ return -ENOTSUPP;
+};
+
+#endif
+
#endif /* _LINUX_OF_H */
--
2.17.1
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
WARNING: multiple messages have this Message-ID (diff)
From: Prakhar Srivastava <prsriva@linux.microsoft.com>
To: linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-integrity@vger.kernel.org, kexec@lists.infradead.org
Cc: arnd@arndb.de, jean-philippe@linaro.org, allison@lohutok.net,
kristina.martsenko@arm.org, yamada.masahiro@socionext.com,
duwe@lst.de, mark.rutland@arm.com, tglx@linutronix.de,
takahiro.akashi@linaro.org, james.morse@arm.org,
catalin.marinas@arm.com, sboyd@kernel.org,
bauerman@linux.ibm.com, zohar@linux.ibm.com
Subject: [PATCH v2 1/2] Add support for arm64 to carry ima measurement log in kexec_file_load
Date: Mon, 7 Oct 2019 11:59:42 -0700 [thread overview]
Message-ID: <20191007185943.1828-2-prsriva@linux.microsoft.com> (raw)
In-Reply-To: <20191007185943.1828-1-prsriva@linux.microsoft.com>
During kexec_file_load, carrying forward the ima measurement log allows
a verifying party to get the entire runtime event log since the last
full reboot since that is when PCRs were last reset.
Signed-off-by: Prakhar Srivastava <prsriva@linux.microsoft.com>
---
arch/Kconfig | 6 +-
arch/arm64/include/asm/ima.h | 24 +++
arch/arm64/include/asm/kexec.h | 5 +
arch/arm64/kernel/Makefile | 3 +-
arch/arm64/kernel/ima_kexec.c | 78 ++++++++++
arch/arm64/kernel/machine_kexec_file.c | 6 +
drivers/of/Kconfig | 6 +
drivers/of/Makefile | 1 +
drivers/of/of_ima.c | 204 +++++++++++++++++++++++++
include/linux/of.h | 31 ++++
10 files changed, 362 insertions(+), 2 deletions(-)
create mode 100644 arch/arm64/include/asm/ima.h
create mode 100644 arch/arm64/kernel/ima_kexec.c
create mode 100644 drivers/of/of_ima.c
diff --git a/arch/Kconfig b/arch/Kconfig
index a7b57dd42c26..d53e1596c5b1 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -19,7 +19,11 @@ config KEXEC_CORE
bool
config HAVE_IMA_KEXEC
- bool
+ bool "Carry over IMA measurement log during kexec_file_load() syscall"
+ depends on KEXEC_FILE
+ help
+ Select this option to carry over IMA measurement log during
+ kexec_file_load.
config HOTPLUG_SMT
bool
diff --git a/arch/arm64/include/asm/ima.h b/arch/arm64/include/asm/ima.h
new file mode 100644
index 000000000000..287dbcefd15e
--- /dev/null
+++ b/arch/arm64/include/asm/ima.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ARM64_IMA_H
+#define _ASM_ARM64_IMA_H
+
+struct kimage;
+
+int ima_get_kexec_buffer(void **addr, size_t *size);
+int ima_free_kexec_buffer(void);
+void remove_ima_buffer(void *fdt, int chosen_node);
+
+#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 setup_ima_buffer(const struct kimage *image, void *fdt,
+ int chosen_node)
+{
+ remove_ima_buffer(fdt, chosen_node);
+ return 0;
+}
+#endif /* CONFIG_IMA_KEXEC */
+#endif /* _ASM_ARM64_IMA_H */
diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
index 12a561a54128..e8d2412066e7 100644
--- a/arch/arm64/include/asm/kexec.h
+++ b/arch/arm64/include/asm/kexec.h
@@ -96,6 +96,11 @@ static inline void crash_post_resume(void) {}
struct kimage_arch {
void *dtb;
unsigned long dtb_mem;
+
+#ifdef CONFIG_IMA_KEXEC
+ phys_addr_t ima_buffer_addr;
+ size_t ima_buffer_size;
+#endif
};
extern const struct kexec_file_ops kexec_image_ops;
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 478491f07b4f..580238f2e9a7 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -55,7 +55,8 @@ obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o
obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o relocate_kernel.o \
cpu-reset.o
-obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o kexec_image.o
+obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o kexec_image.o \
+ ima_kexec.o
obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o
arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
diff --git a/arch/arm64/kernel/ima_kexec.c b/arch/arm64/kernel/ima_kexec.c
new file mode 100644
index 000000000000..c2450aaa42c8
--- /dev/null
+++ b/arch/arm64/kernel/ima_kexec.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Authors:
+ * Prakhar Srivastava <prsriva@linux.microsoft.com>
+ */
+
+#include <linux/kexec.h>
+#include <linux/of.h>
+
+/**
+ * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
+ * The IMA measurement buffer once read needs to be freed.
+ */
+void remove_ima_buffer(void *fdt, int chosen_node)
+{
+ fdt_remove_ima_buffer(fdt, chosen_node);
+}
+
+/**
+ * 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)
+{
+ return of_get_ima_buffer(addr, size);
+}
+
+/**
+ * ima_free_kexec_buffer - free memory used by the IMA buffer
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int ima_free_kexec_buffer(void)
+{
+ return of_remove_ima_buffer();
+}
+
+#ifdef CONFIG_IMA_KEXEC
+/**
+ * arch_ima_add_kexec_buffer - do arch-specific steps to add the IMA
+ * measurement log.
+ * @image: - pointer to the kimage, to store the address and size of the
+ * IMA measurement log.
+ * @load_addr: - the address where the IMA measurement log is stored.
+ * @size - size of the IMA measurement log.
+ *
+ * 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;
+}
+
+/**
+ * setup_ima_buffer - update the fdt to contain the ima mesasurement log
+ * @image: - pointer to the kimage, containing the address and size of
+ * the IMA measurement log.
+ * @fdt: - pointer to the fdt.
+ * @chosen_node: - node under which property is to be defined.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node)
+{
+ return fdt_setup_ima_buffer(image->arch.ima_buffer_addr,
+ image->arch.ima_buffer_size,
+ fdt, chosen_node);
+
+}
+#endif /* CONFIG_IMA_KEXEC */
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index 58871333737a..86d57198d739 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -21,6 +21,7 @@
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <asm/byteorder.h>
+#include <asm/ima.h>
/* relevant device tree properties */
#define FDT_PROP_INITRD_START "linux,initrd-start"
@@ -85,6 +86,11 @@ static int setup_dtb(struct kimage *image,
goto out;
}
+ /* add ima measuremnet log buffer */
+ ret = setup_ima_buffer(image, dtb, off);
+ if (ret < 0)
+ goto out;
+
/* add kaslr-seed */
ret = fdt_delprop(dtb, off, FDT_PROP_KASLR_SEED);
if (ret == -FDT_ERR_NOTFOUND)
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 37c2ccbefecd..167c6ecb64aa 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -103,4 +103,10 @@ config OF_OVERLAY
config OF_NUMA
bool
+config OF_IMA
+ def_bool y
+ help
+ IMA related wrapper functions to add/remove ima measurement logs during
+ kexec_file_load call.
+
endif # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 663a4af0cccd..b4caf083df4e 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -14,5 +14,6 @@ obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
obj-$(CONFIG_OF_RESOLVE) += resolver.o
obj-$(CONFIG_OF_OVERLAY) += overlay.o
obj-$(CONFIG_OF_NUMA) += of_numa.o
+obj-$(CONFIG_OF_IMA) += of_ima.o
obj-$(CONFIG_OF_UNITTEST) += unittest-data/
diff --git a/drivers/of/of_ima.c b/drivers/of/of_ima.c
new file mode 100644
index 000000000000..cfc3cb4522b0
--- /dev/null
+++ b/drivers/of/of_ima.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ */
+
+#include <linux/slab.h>
+#include <linux/kexec.h>
+#include <linux/of.h>
+#include <linux/memblock.h>
+#include <linux/libfdt.h>
+
+/**
+ * delete_fdt_mem_rsv - delete memory reservation with given address and size
+ * @fdt - pointer to the fdt.
+ * @start - start address of the memory.
+ * @size - number of cells to be deletd.
+ *
+ * Return: 0 on success, or negative errno on error.
+ */
+int fdt_delete_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 < 0) {
+ pr_err("Malformed device tree\n");
+ return ret;
+ }
+
+ if (rsv_start == start && rsv_size == size) {
+ ret = fdt_del_mem_rsv(fdt, i);
+ if (ret < 0) {
+ pr_err("Error deleting device tree reservation\n");
+ return ret;
+ }
+
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * of_get_ima_buffer_properties - get the properties for ima buffer
+ * @ima_buf_start - start of the ima buffer
+ * @ima_buf_end - end of the ima buffer
+ * If any one of the properties is not found. The device tree
+ * is malformed or something went wrong.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int of_get_ima_buffer_properties(void **ima_buf_start, void **ima_buf_end)
+{
+ struct property *pproperty;
+
+ pproperty = of_find_property(of_chosen, "linux,ima-kexec-buffer",
+ NULL);
+ *ima_buf_start = pproperty ? pproperty->value : NULL;
+
+ pproperty = of_find_property(of_chosen, "linux,ima-kexec-buffer-end",
+ NULL);
+ *ima_buf_end = pproperty ? pproperty->value : NULL;
+
+ if (!*ima_buf_start || !*ima_buf_end)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * of_remove_ima_buffer - free memory used by the IMA buffer
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int of_remove_ima_buffer(void)
+{
+ int ret;
+ void *ima_buf_start, *ima_buf_end;
+ uint64_t buf_start, buf_end;
+
+ ret = of_get_ima_buffer_properties(&ima_buf_start, &ima_buf_end);
+ if (ret < 0)
+ return ret;
+
+ buf_start = fdt64_to_cpu(*((const fdt64_t *) ima_buf_start));
+ buf_end = fdt64_to_cpu(*((const fdt64_t *) ima_buf_end));
+
+ ret = of_remove_property(of_chosen, ima_buf_start);
+ if (ret < 0)
+ return ret;
+
+ ret = of_remove_property(of_chosen, ima_buf_end);
+ if (ret < 0)
+ return ret;
+
+ return memblock_free(buf_start, buf_end - buf_start);
+}
+
+/**
+ * of_get_ima_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 of_get_ima_buffer(void **addr, size_t *size)
+{
+ int ret;
+ void *ima_buf_start, *ima_buf_end;
+ uint64_t buf_start, buf_end;
+
+ ret = of_get_ima_buffer_properties(&ima_buf_start, &ima_buf_end);
+ if (ret < 0)
+ return ret;
+
+ buf_start = fdt64_to_cpu(*((const fdt64_t *) ima_buf_start));
+ buf_end = fdt64_to_cpu(*((const fdt64_t *) ima_buf_end));
+
+ *addr = __va(buf_start);
+ *size = buf_end - buf_start;
+
+ return 0;
+}
+
+/**
+ * fdt_remove_ima_buffer - remove the IMA buffer property and reservation
+ * @fdt - pointer the fdt.
+ * @chosen_node - node under which property can be found.
+ *
+ * The IMA measurement buffer is either read by now and freeed or a kexec call
+ * needs to replace the ima measurement buffer, clear the property and memory
+ * reservation.
+ */
+void fdt_remove_ima_buffer(void *fdt, int chosen_node)
+{
+ int ret, len;
+ const void *prop;
+ uint64_t tmp_start, tmp_end;
+
+ prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len);
+ if (prop) {
+ tmp_start = fdt64_to_cpu(*((const fdt64_t *) prop));
+
+ prop = fdt_getprop(fdt, chosen_node,
+ "linux,ima-kexec-buffer-end", &len);
+ if (!prop)
+ return;
+
+ tmp_end = fdt64_to_cpu(*((const fdt64_t *) prop));
+
+ ret = fdt_delete_mem_rsv(fdt, tmp_start, tmp_end - tmp_start);
+
+ if (ret == 0)
+ pr_debug("Removed old IMA buffer reservation.\n");
+ else if (ret != -ENOENT)
+ return;
+
+ fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer");
+ fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer-end");
+ }
+}
+
+/**
+ * fdt_setup_ima_buffer - update the fdt to contain the ima mesasurement log
+ * @image: - pointer to the kimage, containing the address and size of
+ * the IMA measurement log.
+ * @fdt: - pointer to the fdt.
+ * @chosen_node: - node under which property is to be defined.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int fdt_setup_ima_buffer(const phys_addr_t ima_buffer_addr,
+ const size_t ima_buffer_size,
+ void *fdt, int chosen_node)
+{
+ int ret;
+
+ fdt_remove_ima_buffer(fdt, chosen_node);
+
+ if (!ima_buffer_addr)
+ return 0;
+
+ ret = fdt_setprop_u64(fdt, chosen_node, "linux,ima-kexec-buffer",
+ ima_buffer_addr);
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_setprop_u64(fdt, chosen_node, "linux,ima-kexec-buffer-end",
+ ima_buffer_addr +
+ ima_buffer_size);
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_add_mem_rsv(fdt, ima_buffer_addr,
+ ima_buffer_size);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
diff --git a/include/linux/of.h b/include/linux/of.h
index 844f89e1b039..7831c2972178 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -1477,4 +1477,35 @@ static inline int of_overlay_notifier_unregister(struct notifier_block *nb)
#endif
+#ifdef CONFIG_OF_IMA
+int of_remove_ima_buffer(void);
+int of_get_ima_buffer(void **addr, size_t *size);
+void fdt_remove_ima_buffer(void *fdt, int chosen_node);
+int fdt_setup_ima_buffer(const phys_addr_t ima_buffer_addr,
+ const size_t ima_buffer_size,
+ void *fdt, int chosen_node);
+#else
+static inline int of_remove_ima_buffer(void)
+{
+ return -ENOTSUPP;
+};
+
+static inline int of_get_ima_buffer(void **addr, size_t *size)
+{
+ return -ENOTSUPP;
+};
+
+static inline void fdt_remove_ima_buffer(void *fdt, int chosen_node)
+{
+ return -ENOTSUPP;
+};
+
+static inline int fdt_setup_ima_buffer(const phys_addr_t ima_buffer_addr,
+ const size_t ima_buffer_size, void *fdt, int chosen_node)
+{
+ return -ENOTSUPP;
+};
+
+#endif
+
#endif /* _LINUX_OF_H */
--
2.17.1
WARNING: multiple messages have this Message-ID (diff)
From: Prakhar Srivastava <prsriva@linux.microsoft.com>
To: linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-integrity@vger.kernel.org, kexec@lists.infradead.org
Cc: mark.rutland@arm.com, jean-philippe@linaro.org, arnd@arndb.de,
takahiro.akashi@linaro.org, sboyd@kernel.org,
catalin.marinas@arm.com, zohar@linux.ibm.com,
yamada.masahiro@socionext.com, kristina.martsenko@arm.org,
duwe@lst.de, bauerman@linux.ibm.com, james.morse@arm.org,
tglx@linutronix.de, allison@lohutok.net
Subject: [PATCH v2 1/2] Add support for arm64 to carry ima measurement log in kexec_file_load
Date: Mon, 7 Oct 2019 11:59:42 -0700 [thread overview]
Message-ID: <20191007185943.1828-2-prsriva@linux.microsoft.com> (raw)
In-Reply-To: <20191007185943.1828-1-prsriva@linux.microsoft.com>
During kexec_file_load, carrying forward the ima measurement log allows
a verifying party to get the entire runtime event log since the last
full reboot since that is when PCRs were last reset.
Signed-off-by: Prakhar Srivastava <prsriva@linux.microsoft.com>
---
arch/Kconfig | 6 +-
arch/arm64/include/asm/ima.h | 24 +++
arch/arm64/include/asm/kexec.h | 5 +
arch/arm64/kernel/Makefile | 3 +-
arch/arm64/kernel/ima_kexec.c | 78 ++++++++++
arch/arm64/kernel/machine_kexec_file.c | 6 +
drivers/of/Kconfig | 6 +
drivers/of/Makefile | 1 +
drivers/of/of_ima.c | 204 +++++++++++++++++++++++++
include/linux/of.h | 31 ++++
10 files changed, 362 insertions(+), 2 deletions(-)
create mode 100644 arch/arm64/include/asm/ima.h
create mode 100644 arch/arm64/kernel/ima_kexec.c
create mode 100644 drivers/of/of_ima.c
diff --git a/arch/Kconfig b/arch/Kconfig
index a7b57dd42c26..d53e1596c5b1 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -19,7 +19,11 @@ config KEXEC_CORE
bool
config HAVE_IMA_KEXEC
- bool
+ bool "Carry over IMA measurement log during kexec_file_load() syscall"
+ depends on KEXEC_FILE
+ help
+ Select this option to carry over IMA measurement log during
+ kexec_file_load.
config HOTPLUG_SMT
bool
diff --git a/arch/arm64/include/asm/ima.h b/arch/arm64/include/asm/ima.h
new file mode 100644
index 000000000000..287dbcefd15e
--- /dev/null
+++ b/arch/arm64/include/asm/ima.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ARM64_IMA_H
+#define _ASM_ARM64_IMA_H
+
+struct kimage;
+
+int ima_get_kexec_buffer(void **addr, size_t *size);
+int ima_free_kexec_buffer(void);
+void remove_ima_buffer(void *fdt, int chosen_node);
+
+#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 setup_ima_buffer(const struct kimage *image, void *fdt,
+ int chosen_node)
+{
+ remove_ima_buffer(fdt, chosen_node);
+ return 0;
+}
+#endif /* CONFIG_IMA_KEXEC */
+#endif /* _ASM_ARM64_IMA_H */
diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
index 12a561a54128..e8d2412066e7 100644
--- a/arch/arm64/include/asm/kexec.h
+++ b/arch/arm64/include/asm/kexec.h
@@ -96,6 +96,11 @@ static inline void crash_post_resume(void) {}
struct kimage_arch {
void *dtb;
unsigned long dtb_mem;
+
+#ifdef CONFIG_IMA_KEXEC
+ phys_addr_t ima_buffer_addr;
+ size_t ima_buffer_size;
+#endif
};
extern const struct kexec_file_ops kexec_image_ops;
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 478491f07b4f..580238f2e9a7 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -55,7 +55,8 @@ obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o
obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o relocate_kernel.o \
cpu-reset.o
-obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o kexec_image.o
+obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o kexec_image.o \
+ ima_kexec.o
obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o
arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
diff --git a/arch/arm64/kernel/ima_kexec.c b/arch/arm64/kernel/ima_kexec.c
new file mode 100644
index 000000000000..c2450aaa42c8
--- /dev/null
+++ b/arch/arm64/kernel/ima_kexec.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Authors:
+ * Prakhar Srivastava <prsriva@linux.microsoft.com>
+ */
+
+#include <linux/kexec.h>
+#include <linux/of.h>
+
+/**
+ * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
+ * The IMA measurement buffer once read needs to be freed.
+ */
+void remove_ima_buffer(void *fdt, int chosen_node)
+{
+ fdt_remove_ima_buffer(fdt, chosen_node);
+}
+
+/**
+ * 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)
+{
+ return of_get_ima_buffer(addr, size);
+}
+
+/**
+ * ima_free_kexec_buffer - free memory used by the IMA buffer
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int ima_free_kexec_buffer(void)
+{
+ return of_remove_ima_buffer();
+}
+
+#ifdef CONFIG_IMA_KEXEC
+/**
+ * arch_ima_add_kexec_buffer - do arch-specific steps to add the IMA
+ * measurement log.
+ * @image: - pointer to the kimage, to store the address and size of the
+ * IMA measurement log.
+ * @load_addr: - the address where the IMA measurement log is stored.
+ * @size - size of the IMA measurement log.
+ *
+ * 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;
+}
+
+/**
+ * setup_ima_buffer - update the fdt to contain the ima mesasurement log
+ * @image: - pointer to the kimage, containing the address and size of
+ * the IMA measurement log.
+ * @fdt: - pointer to the fdt.
+ * @chosen_node: - node under which property is to be defined.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node)
+{
+ return fdt_setup_ima_buffer(image->arch.ima_buffer_addr,
+ image->arch.ima_buffer_size,
+ fdt, chosen_node);
+
+}
+#endif /* CONFIG_IMA_KEXEC */
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index 58871333737a..86d57198d739 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -21,6 +21,7 @@
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <asm/byteorder.h>
+#include <asm/ima.h>
/* relevant device tree properties */
#define FDT_PROP_INITRD_START "linux,initrd-start"
@@ -85,6 +86,11 @@ static int setup_dtb(struct kimage *image,
goto out;
}
+ /* add ima measuremnet log buffer */
+ ret = setup_ima_buffer(image, dtb, off);
+ if (ret < 0)
+ goto out;
+
/* add kaslr-seed */
ret = fdt_delprop(dtb, off, FDT_PROP_KASLR_SEED);
if (ret == -FDT_ERR_NOTFOUND)
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 37c2ccbefecd..167c6ecb64aa 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -103,4 +103,10 @@ config OF_OVERLAY
config OF_NUMA
bool
+config OF_IMA
+ def_bool y
+ help
+ IMA related wrapper functions to add/remove ima measurement logs during
+ kexec_file_load call.
+
endif # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 663a4af0cccd..b4caf083df4e 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -14,5 +14,6 @@ obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
obj-$(CONFIG_OF_RESOLVE) += resolver.o
obj-$(CONFIG_OF_OVERLAY) += overlay.o
obj-$(CONFIG_OF_NUMA) += of_numa.o
+obj-$(CONFIG_OF_IMA) += of_ima.o
obj-$(CONFIG_OF_UNITTEST) += unittest-data/
diff --git a/drivers/of/of_ima.c b/drivers/of/of_ima.c
new file mode 100644
index 000000000000..cfc3cb4522b0
--- /dev/null
+++ b/drivers/of/of_ima.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ */
+
+#include <linux/slab.h>
+#include <linux/kexec.h>
+#include <linux/of.h>
+#include <linux/memblock.h>
+#include <linux/libfdt.h>
+
+/**
+ * delete_fdt_mem_rsv - delete memory reservation with given address and size
+ * @fdt - pointer to the fdt.
+ * @start - start address of the memory.
+ * @size - number of cells to be deletd.
+ *
+ * Return: 0 on success, or negative errno on error.
+ */
+int fdt_delete_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 < 0) {
+ pr_err("Malformed device tree\n");
+ return ret;
+ }
+
+ if (rsv_start == start && rsv_size == size) {
+ ret = fdt_del_mem_rsv(fdt, i);
+ if (ret < 0) {
+ pr_err("Error deleting device tree reservation\n");
+ return ret;
+ }
+
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * of_get_ima_buffer_properties - get the properties for ima buffer
+ * @ima_buf_start - start of the ima buffer
+ * @ima_buf_end - end of the ima buffer
+ * If any one of the properties is not found. The device tree
+ * is malformed or something went wrong.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int of_get_ima_buffer_properties(void **ima_buf_start, void **ima_buf_end)
+{
+ struct property *pproperty;
+
+ pproperty = of_find_property(of_chosen, "linux,ima-kexec-buffer",
+ NULL);
+ *ima_buf_start = pproperty ? pproperty->value : NULL;
+
+ pproperty = of_find_property(of_chosen, "linux,ima-kexec-buffer-end",
+ NULL);
+ *ima_buf_end = pproperty ? pproperty->value : NULL;
+
+ if (!*ima_buf_start || !*ima_buf_end)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * of_remove_ima_buffer - free memory used by the IMA buffer
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int of_remove_ima_buffer(void)
+{
+ int ret;
+ void *ima_buf_start, *ima_buf_end;
+ uint64_t buf_start, buf_end;
+
+ ret = of_get_ima_buffer_properties(&ima_buf_start, &ima_buf_end);
+ if (ret < 0)
+ return ret;
+
+ buf_start = fdt64_to_cpu(*((const fdt64_t *) ima_buf_start));
+ buf_end = fdt64_to_cpu(*((const fdt64_t *) ima_buf_end));
+
+ ret = of_remove_property(of_chosen, ima_buf_start);
+ if (ret < 0)
+ return ret;
+
+ ret = of_remove_property(of_chosen, ima_buf_end);
+ if (ret < 0)
+ return ret;
+
+ return memblock_free(buf_start, buf_end - buf_start);
+}
+
+/**
+ * of_get_ima_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 of_get_ima_buffer(void **addr, size_t *size)
+{
+ int ret;
+ void *ima_buf_start, *ima_buf_end;
+ uint64_t buf_start, buf_end;
+
+ ret = of_get_ima_buffer_properties(&ima_buf_start, &ima_buf_end);
+ if (ret < 0)
+ return ret;
+
+ buf_start = fdt64_to_cpu(*((const fdt64_t *) ima_buf_start));
+ buf_end = fdt64_to_cpu(*((const fdt64_t *) ima_buf_end));
+
+ *addr = __va(buf_start);
+ *size = buf_end - buf_start;
+
+ return 0;
+}
+
+/**
+ * fdt_remove_ima_buffer - remove the IMA buffer property and reservation
+ * @fdt - pointer the fdt.
+ * @chosen_node - node under which property can be found.
+ *
+ * The IMA measurement buffer is either read by now and freeed or a kexec call
+ * needs to replace the ima measurement buffer, clear the property and memory
+ * reservation.
+ */
+void fdt_remove_ima_buffer(void *fdt, int chosen_node)
+{
+ int ret, len;
+ const void *prop;
+ uint64_t tmp_start, tmp_end;
+
+ prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len);
+ if (prop) {
+ tmp_start = fdt64_to_cpu(*((const fdt64_t *) prop));
+
+ prop = fdt_getprop(fdt, chosen_node,
+ "linux,ima-kexec-buffer-end", &len);
+ if (!prop)
+ return;
+
+ tmp_end = fdt64_to_cpu(*((const fdt64_t *) prop));
+
+ ret = fdt_delete_mem_rsv(fdt, tmp_start, tmp_end - tmp_start);
+
+ if (ret == 0)
+ pr_debug("Removed old IMA buffer reservation.\n");
+ else if (ret != -ENOENT)
+ return;
+
+ fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer");
+ fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer-end");
+ }
+}
+
+/**
+ * fdt_setup_ima_buffer - update the fdt to contain the ima mesasurement log
+ * @image: - pointer to the kimage, containing the address and size of
+ * the IMA measurement log.
+ * @fdt: - pointer to the fdt.
+ * @chosen_node: - node under which property is to be defined.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int fdt_setup_ima_buffer(const phys_addr_t ima_buffer_addr,
+ const size_t ima_buffer_size,
+ void *fdt, int chosen_node)
+{
+ int ret;
+
+ fdt_remove_ima_buffer(fdt, chosen_node);
+
+ if (!ima_buffer_addr)
+ return 0;
+
+ ret = fdt_setprop_u64(fdt, chosen_node, "linux,ima-kexec-buffer",
+ ima_buffer_addr);
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_setprop_u64(fdt, chosen_node, "linux,ima-kexec-buffer-end",
+ ima_buffer_addr +
+ ima_buffer_size);
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_add_mem_rsv(fdt, ima_buffer_addr,
+ ima_buffer_size);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
diff --git a/include/linux/of.h b/include/linux/of.h
index 844f89e1b039..7831c2972178 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -1477,4 +1477,35 @@ static inline int of_overlay_notifier_unregister(struct notifier_block *nb)
#endif
+#ifdef CONFIG_OF_IMA
+int of_remove_ima_buffer(void);
+int of_get_ima_buffer(void **addr, size_t *size);
+void fdt_remove_ima_buffer(void *fdt, int chosen_node);
+int fdt_setup_ima_buffer(const phys_addr_t ima_buffer_addr,
+ const size_t ima_buffer_size,
+ void *fdt, int chosen_node);
+#else
+static inline int of_remove_ima_buffer(void)
+{
+ return -ENOTSUPP;
+};
+
+static inline int of_get_ima_buffer(void **addr, size_t *size)
+{
+ return -ENOTSUPP;
+};
+
+static inline void fdt_remove_ima_buffer(void *fdt, int chosen_node)
+{
+ return -ENOTSUPP;
+};
+
+static inline int fdt_setup_ima_buffer(const phys_addr_t ima_buffer_addr,
+ const size_t ima_buffer_size, void *fdt, int chosen_node)
+{
+ return -ENOTSUPP;
+};
+
+#endif
+
#endif /* _LINUX_OF_H */
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2019-10-07 18:59 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-10-07 18:59 [PATCH v2 0/2] Add support to carry ima measurement log in kexec_file_load Prakhar Srivastava
2019-10-07 18:59 ` Prakhar Srivastava
2019-10-07 18:59 ` Prakhar Srivastava
2019-10-07 18:59 ` Prakhar Srivastava [this message]
2019-10-07 18:59 ` [PATCH v2 1/2] Add support for arm64 " Prakhar Srivastava
2019-10-07 18:59 ` Prakhar Srivastava
2019-10-08 21:22 ` Sasha Levin
2019-10-08 21:22 ` Sasha Levin
2019-10-08 21:22 ` Sasha Levin
2019-10-09 20:49 ` prsriva
2019-10-09 20:49 ` prsriva
2019-10-09 20:49 ` prsriva
2019-10-07 18:59 ` [PATCH v2 2/2] update powerpc implementation to call into of_ima* Prakhar Srivastava
2019-10-07 18:59 ` Prakhar Srivastava
2019-10-07 18:59 ` Prakhar Srivastava
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191007185943.1828-2-prsriva@linux.microsoft.com \
--to=prsriva@linux.microsoft.com \
--cc=allison@lohutok.net \
--cc=arnd@arndb.de \
--cc=bauerman@linux.ibm.com \
--cc=catalin.marinas@arm.com \
--cc=duwe@lst.de \
--cc=james.morse@arm.org \
--cc=jean-philippe@linaro.org \
--cc=kexec@lists.infradead.org \
--cc=kristina.martsenko@arm.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=sboyd@kernel.org \
--cc=takahiro.akashi@linaro.org \
--cc=tglx@linutronix.de \
--cc=yamada.masahiro@socionext.com \
--cc=zohar@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.