All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] kexec_file: Add buffer hand-over for the next kernel
@ 2016-06-21  1:44 ` Thiago Jung Bauermann
  0 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: kexec, x86, linux-kernel, Eric Biederman, Dave Young,
	Michael Ellerman, Mimi Zohar, Eric Richter,
	Thiago Jung Bauermann

Hello,

This patch series implements a mechanism which allows the kernel to pass on
a buffer to the kernel that will be kexec'd. This buffer is passed as a
segment which is added to the kimage when it is being prepared by
kexec_file_load.

How the second kernel is informed of this buffer is architecture-specific.
On PowerPC, this is done via the device tree, by checking the properties
/chosen/linux,kexec-handover-buffer-start and
/chosen/linux,kexec-handover-buffer-end, which is analogous to how the
kernel finds the initrd.

This feature was implemented because the Integrity Measurement Architecture
subsystem needs to preserve its measurement list accross the kexec reboot.
This is so that IMA can implement trusted boot support on the OpenPower
platform, because on such systems an intermediary Linux instance running as
part of the firmware is used to boot the target operating system via kexec.
Using this mechanism, IMA on this intermediary instance can hand over to the
target OS the measurements of the components that were used to boot it.

Because there could be additional measurement events between the
kexec_file_load call and the actual reboot, IMA needs a way to update the
buffer with those additional events before rebooting. One can minimize
the interval between the kexec_file_load and the reboot syscalls, but as
small as it can be, there is always the possibility that the measurement
list will be out of date at the time of reboot.

To address this issue, this patch series also introduces kexec_update_segment,
which allows a reboot notifier to change the contents of the image segment
during the reboot process.

There's one patch which makes kimage_load_normal_segment and
kexec_update_segment share code. It's not much code that they can share
though, so I'm not sure if it's worth including this patch.

The last patch is not intended to be merged, it just demonstrates how this
feature can be used.

This series applies on top of v2 of the "kexec_file_load implementation
for PowerPC" patch series at:

http://lists.infradead.org/pipermail/kexec/2016-June/016078.html

Thiago Jung Bauermann (6):
  kexec_file: Add buffer hand-over support for the next kernel
  powerpc: kexec_file: Add buffer hand-over support for the next kernel
  kexec_file: Allow skipping checksum calculation for some segments.
  kexec_file: Add mechanism to update kexec segments.
  kexec: Share logic to copy segment page contents.
  IMA: Demonstration code for kexec buffer passing.

 arch/powerpc/include/asm/kexec.h       |   9 ++
 arch/powerpc/kernel/kexec_elf_64.c     |  50 +++++++-
 arch/powerpc/kernel/machine_kexec_64.c |  64 ++++++++++
 arch/x86/kernel/crash.c                |   4 +-
 arch/x86/kernel/kexec-bzimage64.c      |   6 +-
 include/linux/ima.h                    |  11 ++
 include/linux/kexec.h                  |  47 +++++++-
 kernel/kexec_core.c                    | 205 ++++++++++++++++++++++++++-------
 kernel/kexec_file.c                    | 102 ++++++++++++++--
 security/integrity/ima/ima.h           |   5 +
 security/integrity/ima/ima_init.c      |  26 +++++
 security/integrity/ima/ima_template.c  |  79 +++++++++++++
 12 files changed, 547 insertions(+), 61 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 0/6] kexec_file: Add buffer hand-over for the next kernel
@ 2016-06-21  1:44 ` Thiago Jung Bauermann
  0 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Michael Ellerman, x86, kexec, linux-kernel, Eric Biederman,
	Thiago Jung Bauermann, Mimi Zohar, Dave Young, Eric Richter

Hello,

This patch series implements a mechanism which allows the kernel to pass on
a buffer to the kernel that will be kexec'd. This buffer is passed as a
segment which is added to the kimage when it is being prepared by
kexec_file_load.

How the second kernel is informed of this buffer is architecture-specific.
On PowerPC, this is done via the device tree, by checking the properties
/chosen/linux,kexec-handover-buffer-start and
/chosen/linux,kexec-handover-buffer-end, which is analogous to how the
kernel finds the initrd.

This feature was implemented because the Integrity Measurement Architecture
subsystem needs to preserve its measurement list accross the kexec reboot.
This is so that IMA can implement trusted boot support on the OpenPower
platform, because on such systems an intermediary Linux instance running as
part of the firmware is used to boot the target operating system via kexec.
Using this mechanism, IMA on this intermediary instance can hand over to the
target OS the measurements of the components that were used to boot it.

Because there could be additional measurement events between the
kexec_file_load call and the actual reboot, IMA needs a way to update the
buffer with those additional events before rebooting. One can minimize
the interval between the kexec_file_load and the reboot syscalls, but as
small as it can be, there is always the possibility that the measurement
list will be out of date at the time of reboot.

To address this issue, this patch series also introduces kexec_update_segment,
which allows a reboot notifier to change the contents of the image segment
during the reboot process.

There's one patch which makes kimage_load_normal_segment and
kexec_update_segment share code. It's not much code that they can share
though, so I'm not sure if it's worth including this patch.

The last patch is not intended to be merged, it just demonstrates how this
feature can be used.

This series applies on top of v2 of the "kexec_file_load implementation
for PowerPC" patch series at:

http://lists.infradead.org/pipermail/kexec/2016-June/016078.html

Thiago Jung Bauermann (6):
  kexec_file: Add buffer hand-over support for the next kernel
  powerpc: kexec_file: Add buffer hand-over support for the next kernel
  kexec_file: Allow skipping checksum calculation for some segments.
  kexec_file: Add mechanism to update kexec segments.
  kexec: Share logic to copy segment page contents.
  IMA: Demonstration code for kexec buffer passing.

 arch/powerpc/include/asm/kexec.h       |   9 ++
 arch/powerpc/kernel/kexec_elf_64.c     |  50 +++++++-
 arch/powerpc/kernel/machine_kexec_64.c |  64 ++++++++++
 arch/x86/kernel/crash.c                |   4 +-
 arch/x86/kernel/kexec-bzimage64.c      |   6 +-
 include/linux/ima.h                    |  11 ++
 include/linux/kexec.h                  |  47 +++++++-
 kernel/kexec_core.c                    | 205 ++++++++++++++++++++++++++-------
 kernel/kexec_file.c                    | 102 ++++++++++++++--
 security/integrity/ima/ima.h           |   5 +
 security/integrity/ima/ima_init.c      |  26 +++++
 security/integrity/ima/ima_template.c  |  79 +++++++++++++
 12 files changed, 547 insertions(+), 61 deletions(-)

-- 
1.9.1


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 1/6] kexec_file: Add buffer hand-over support for the next kernel
  2016-06-21  1:44 ` Thiago Jung Bauermann
@ 2016-06-21  1:44   ` Thiago Jung Bauermann
  -1 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: kexec, x86, linux-kernel, Eric Biederman, Dave Young,
	Michael Ellerman, Mimi Zohar, Eric Richter,
	Thiago Jung Bauermann

The buffer hand-over mechanism allows the currently running kernel to pass
data to kernel that will be kexec'd via a kexec segment. The second kernel
can check whether the previous kernel sent data and retrieve it.

This is the architecture-independent part of the feature.

Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
 include/linux/kexec.h | 40 ++++++++++++++++++++++++++
 kernel/kexec_file.c   | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+)

diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index a08cd986b5a1..72db95c623b3 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -325,6 +325,46 @@ int __weak arch_kexec_walk_mem(unsigned int image_type, unsigned long start,
 void arch_kexec_protect_crashkres(void);
 void arch_kexec_unprotect_crashkres(void);
 
+#ifdef CONFIG_KEXEC_FILE
+bool __weak kexec_can_hand_over_buffer(void);
+int __weak arch_kexec_add_handover_buffer(struct kimage *image,
+					  unsigned long load_addr,
+					  unsigned long size);
+int kexec_add_handover_buffer(struct kimage *image, void *buffer,
+			      unsigned long bufsz, unsigned long memsz,
+			      unsigned long buf_align, unsigned long buf_min,
+			      unsigned long buf_max, bool top_down,
+			      unsigned long *load_addr);
+int __weak kexec_get_handover_buffer(void **addr, unsigned long *size);
+int __weak kexec_free_handover_buffer(void);
+#else
+static inline bool kexec_can_hand_over_buffer(void)
+{
+	return false;
+}
+
+static inline int kexec_add_handover_buffer(struct kimage *image, void *buffer,
+					    unsigned long bufsz,
+					    unsigned long memsz,
+					    unsigned long buf_align,
+					    unsigned long buf_min,
+					    unsigned long buf_max,
+					    bool top_down, bool checksum,
+					    unsigned long *load_addr)
+{
+	return -ENOTSUPP;
+}
+
+static inline int kexec_get_handover_buffer(void **addr, unsigned long *size)
+{
+	return -ENOTSUPP;
+}
+
+static inline int kexec_free_handover_buffer(void)
+{
+	return -ENOTSUPP;
+}
+#endif /* CONFIG_KEXEC_FILE */
 #else /* !CONFIG_KEXEC_CORE */
 struct pt_regs;
 struct task_struct;
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 3e494261d32a..d6ba702654f5 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -113,6 +113,85 @@ void kimage_file_post_load_cleanup(struct kimage *image)
 	image->image_loader_data = NULL;
 }
 
+/**
+ * kexec_can_hand_over_buffer - can we pass data to the kexec'd kernel?
+ */
+bool __weak kexec_can_hand_over_buffer(void)
+{
+	return false;
+}
+
+/**
+ * arch_kexec_add_handover_buffer - do arch-specific steps to handover buffer
+ *
+ * Architectures should use this function to pass on the handover buffer
+ * information to the next kernel.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int __weak arch_kexec_add_handover_buffer(struct kimage *image,
+					  unsigned long load_addr,
+					  unsigned long size)
+{
+	return -ENOTSUPP;
+}
+
+/**
+ * kexec_add_handover_buffer - add buffer to be used by the next kernel
+ * @image:	kexec image to add buffer to.
+ * @buffer:	Contents of the handover buffer.
+ * @bufsz:	@buffer size.
+ * @memsz:	Handover buffer size in memory.
+ * @buf_align:	Buffer alignment restriction.
+ * @buf_min:	Minimum address where buffer can be placed.
+ * @buf_max:	Maximum address where buffer can be placed.
+ * @top_down:	Find the highest available memory position for the buffer?
+ * @load_addr:	On successful return, set to the physical memory address of the
+ * 		buffer in the next kernel.
+ *
+ * This function assumes that kexec_mutex is held.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int kexec_add_handover_buffer(struct kimage *image, void *buffer,
+			      unsigned long bufsz, unsigned long memsz,
+			      unsigned long buf_align, unsigned long buf_min,
+			      unsigned long buf_max, bool top_down,
+			      unsigned long *load_addr)
+{
+	int ret;
+
+	if (!kexec_can_hand_over_buffer())
+		return -ENOTSUPP;
+
+	ret = kexec_add_buffer(image, buffer, bufsz, memsz, buf_align, buf_min,
+			       buf_max, top_down, load_addr);
+	if (ret)
+		return ret;
+
+	return arch_kexec_add_handover_buffer(image, *load_addr, memsz);
+}
+
+/**
+ * kexec_get_handover_buffer - get the handover 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 __weak kexec_get_handover_buffer(void **addr, unsigned long *size)
+{
+	return -ENOTSUPP;
+}
+
+/**
+ * kexec_free_handover_buffer - free memory used by the handover buffer
+ */
+int __weak kexec_free_handover_buffer(void)
+{
+	return -ENOTSUPP;
+}
+
 /*
  * In file mode list of segments is prepared by kernel. Copy relevant
  * data from user space, do error checking, prepare segment list
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 1/6] kexec_file: Add buffer hand-over support for the next kernel
@ 2016-06-21  1:44   ` Thiago Jung Bauermann
  0 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Michael Ellerman, x86, kexec, linux-kernel, Eric Biederman,
	Thiago Jung Bauermann, Mimi Zohar, Dave Young, Eric Richter

The buffer hand-over mechanism allows the currently running kernel to pass
data to kernel that will be kexec'd via a kexec segment. The second kernel
can check whether the previous kernel sent data and retrieve it.

This is the architecture-independent part of the feature.

Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
 include/linux/kexec.h | 40 ++++++++++++++++++++++++++
 kernel/kexec_file.c   | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+)

diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index a08cd986b5a1..72db95c623b3 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -325,6 +325,46 @@ int __weak arch_kexec_walk_mem(unsigned int image_type, unsigned long start,
 void arch_kexec_protect_crashkres(void);
 void arch_kexec_unprotect_crashkres(void);
 
+#ifdef CONFIG_KEXEC_FILE
+bool __weak kexec_can_hand_over_buffer(void);
+int __weak arch_kexec_add_handover_buffer(struct kimage *image,
+					  unsigned long load_addr,
+					  unsigned long size);
+int kexec_add_handover_buffer(struct kimage *image, void *buffer,
+			      unsigned long bufsz, unsigned long memsz,
+			      unsigned long buf_align, unsigned long buf_min,
+			      unsigned long buf_max, bool top_down,
+			      unsigned long *load_addr);
+int __weak kexec_get_handover_buffer(void **addr, unsigned long *size);
+int __weak kexec_free_handover_buffer(void);
+#else
+static inline bool kexec_can_hand_over_buffer(void)
+{
+	return false;
+}
+
+static inline int kexec_add_handover_buffer(struct kimage *image, void *buffer,
+					    unsigned long bufsz,
+					    unsigned long memsz,
+					    unsigned long buf_align,
+					    unsigned long buf_min,
+					    unsigned long buf_max,
+					    bool top_down, bool checksum,
+					    unsigned long *load_addr)
+{
+	return -ENOTSUPP;
+}
+
+static inline int kexec_get_handover_buffer(void **addr, unsigned long *size)
+{
+	return -ENOTSUPP;
+}
+
+static inline int kexec_free_handover_buffer(void)
+{
+	return -ENOTSUPP;
+}
+#endif /* CONFIG_KEXEC_FILE */
 #else /* !CONFIG_KEXEC_CORE */
 struct pt_regs;
 struct task_struct;
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 3e494261d32a..d6ba702654f5 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -113,6 +113,85 @@ void kimage_file_post_load_cleanup(struct kimage *image)
 	image->image_loader_data = NULL;
 }
 
+/**
+ * kexec_can_hand_over_buffer - can we pass data to the kexec'd kernel?
+ */
+bool __weak kexec_can_hand_over_buffer(void)
+{
+	return false;
+}
+
+/**
+ * arch_kexec_add_handover_buffer - do arch-specific steps to handover buffer
+ *
+ * Architectures should use this function to pass on the handover buffer
+ * information to the next kernel.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int __weak arch_kexec_add_handover_buffer(struct kimage *image,
+					  unsigned long load_addr,
+					  unsigned long size)
+{
+	return -ENOTSUPP;
+}
+
+/**
+ * kexec_add_handover_buffer - add buffer to be used by the next kernel
+ * @image:	kexec image to add buffer to.
+ * @buffer:	Contents of the handover buffer.
+ * @bufsz:	@buffer size.
+ * @memsz:	Handover buffer size in memory.
+ * @buf_align:	Buffer alignment restriction.
+ * @buf_min:	Minimum address where buffer can be placed.
+ * @buf_max:	Maximum address where buffer can be placed.
+ * @top_down:	Find the highest available memory position for the buffer?
+ * @load_addr:	On successful return, set to the physical memory address of the
+ * 		buffer in the next kernel.
+ *
+ * This function assumes that kexec_mutex is held.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int kexec_add_handover_buffer(struct kimage *image, void *buffer,
+			      unsigned long bufsz, unsigned long memsz,
+			      unsigned long buf_align, unsigned long buf_min,
+			      unsigned long buf_max, bool top_down,
+			      unsigned long *load_addr)
+{
+	int ret;
+
+	if (!kexec_can_hand_over_buffer())
+		return -ENOTSUPP;
+
+	ret = kexec_add_buffer(image, buffer, bufsz, memsz, buf_align, buf_min,
+			       buf_max, top_down, load_addr);
+	if (ret)
+		return ret;
+
+	return arch_kexec_add_handover_buffer(image, *load_addr, memsz);
+}
+
+/**
+ * kexec_get_handover_buffer - get the handover 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 __weak kexec_get_handover_buffer(void **addr, unsigned long *size)
+{
+	return -ENOTSUPP;
+}
+
+/**
+ * kexec_free_handover_buffer - free memory used by the handover buffer
+ */
+int __weak kexec_free_handover_buffer(void)
+{
+	return -ENOTSUPP;
+}
+
 /*
  * In file mode list of segments is prepared by kernel. Copy relevant
  * data from user space, do error checking, prepare segment list
-- 
1.9.1


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 2/6] powerpc: kexec_file: Add buffer hand-over support for the next kernel
  2016-06-21  1:44 ` Thiago Jung Bauermann
@ 2016-06-21  1:44   ` Thiago Jung Bauermann
  -1 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: kexec, x86, linux-kernel, Eric Biederman, Dave Young,
	Michael Ellerman, Mimi Zohar, Eric Richter,
	Thiago Jung Bauermann

The buffer hand-over mechanism allows the currently running kernel to pass
data to kernel that will be kexec'd via a kexec segment. The second kernel
can check whether the previous kernel sent data and retrieve it.

This is the architecture-specific part.

Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/kexec.h       |  9 +++++
 arch/powerpc/kernel/kexec_elf_64.c     | 44 +++++++++++++++++++++++
 arch/powerpc/kernel/machine_kexec_64.c | 64 ++++++++++++++++++++++++++++++++++
 3 files changed, 117 insertions(+)

diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
index a46f5f45570c..9b1ff59bc188 100644
--- a/arch/powerpc/include/asm/kexec.h
+++ b/arch/powerpc/include/asm/kexec.h
@@ -55,6 +55,15 @@ typedef void (*crash_shutdown_t)(void);
 
 #ifdef CONFIG_KEXEC
 
+#ifdef CONFIG_KEXEC_FILE
+#define ARCH_HAS_KIMAGE_ARCH
+
+struct kimage_arch {
+	phys_addr_t handover_buffer_addr;
+	unsigned long handover_buffer_size;
+};
+#endif
+
 /*
  * This function is responsible for capturing register states if coming
  * via panic or invoking dump using sysrq-trigger.
diff --git a/arch/powerpc/kernel/kexec_elf_64.c b/arch/powerpc/kernel/kexec_elf_64.c
index 4e71595300ed..5d2b7036fee7 100644
--- a/arch/powerpc/kernel/kexec_elf_64.c
+++ b/arch/powerpc/kernel/kexec_elf_64.c
@@ -96,6 +96,46 @@ static int elf64_probe(const char *buf, unsigned long len)
 	return elf_check_arch(&ehdr)? 0 : -ENOEXEC;
 }
 
+static int setup_handover_buffer(struct kimage *image, void *fdt,
+				 int chosen_node)
+{
+	int ret;
+
+	if (image->arch.handover_buffer_addr) {
+		ret = fdt_setprop_u64(fdt, chosen_node,
+				      "linux,kexec-handover-buffer-start",
+				      image->arch.handover_buffer_addr);
+		if (ret < 0) {
+			pr_err("Error setting up the new device tree.\n");
+			return -EINVAL;
+		}
+
+		/* -end is the first address after the buffer. */
+		ret = fdt_setprop_u64(fdt, chosen_node,
+				      "linux,kexec-handover-buffer-end",
+				      image->arch.handover_buffer_addr +
+				      image->arch.handover_buffer_size);
+		if (ret < 0) {
+			pr_err("Error setting up the new device tree.\n");
+			return -EINVAL;
+		}
+
+		ret = fdt_add_mem_rsv(fdt, image->arch.handover_buffer_addr,
+				      image->arch.handover_buffer_size);
+		if (ret) {
+			pr_err("Error reserving kexec handover buffer: %s\n",
+			       fdt_strerror(ret));
+			return -EINVAL;
+		}
+
+		pr_debug("kexec handover buffer at 0x%llx, size = 0x%lx\n",
+			 image->arch.handover_buffer_addr,
+			 image->arch.handover_buffer_size);
+	}
+
+	return 0;
+}
+
 static bool find_debug_console(void *fdt, int chosen_node)
 {
 	int len;
@@ -494,6 +534,10 @@ void *elf64_load(struct kimage *image, char *kernel_buf,
 		}
 	}
 
+	ret = setup_handover_buffer(image, fdt, chosen_node);
+	if (ret)
+		goto out;
+
 	ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0);
 	if (ret) {
 		pr_err("Error setting up the new device tree.\n");
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index 43e8185ab6f7..c582abf726f5 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -19,6 +19,7 @@
 #include <linux/cpu.h>
 #include <linux/hardirq.h>
 #include <linux/memblock.h>
+#include <linux/libfdt.h>
 
 #include <asm/page.h>
 #include <asm/current.h>
@@ -481,6 +482,69 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
 	return image->fops->cleanup(image->image_loader_data);
 }
 
+bool kexec_can_hand_over_buffer(void)
+{
+	return true;
+}
+
+int arch_kexec_add_handover_buffer(struct kimage *image,
+				   unsigned long load_addr, unsigned long size)
+{
+	image->arch.handover_buffer_addr = load_addr;
+	image->arch.handover_buffer_size = size;
+
+	return 0;
+}
+
+int kexec_get_handover_buffer(void **addr, unsigned long *size)
+{
+	int chosen_node;
+	int startsz, endsz;
+	const void *startp, *endp;
+	unsigned long start_addr, end_addr;
+
+	chosen_node = fdt_path_offset(initial_boot_params, "/chosen");
+	if (chosen_node < 0) {
+		pr_err("Malformed device tree: /chosen not found.\n");
+		return -EINVAL;
+	}
+
+	startp = of_get_flat_dt_prop(chosen_node,
+				     "linux,kexec-handover-buffer-start",
+				     &startsz);
+	endp = of_get_flat_dt_prop(chosen_node,
+				   "linux,kexec-handover-buffer-end",
+				   &endsz);
+	if (!startp || !endp) {
+		pr_debug("kexec handover buffer not found in the device tree.\n");
+		return -ENOENT;
+	}
+
+	start_addr = of_read_number(startp, startsz/4);
+	end_addr = of_read_number(endp, endsz/4);
+
+	*addr =  __va(start_addr);
+	/* -end is the first address after the buffer. */
+	*size = end_addr - start_addr;
+
+	pr_debug("kexec handover buffer at %p, size = %lu\n", *addr, *size);
+
+	return 0;
+}
+
+int kexec_free_handover_buffer(void)
+{
+	int ret;
+	void *addr;
+	unsigned long size;
+
+	ret = kexec_get_handover_buffer(&addr, &size);
+	if (ret)
+		return ret;
+
+	return memblock_free((phys_addr_t) addr, size);
+}
+
 /**
  * arch_kexec_walk_mem - call func(data) for each unreserved memory block
  * @image_type:	kimage.type
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 2/6] powerpc: kexec_file: Add buffer hand-over support for the next kernel
@ 2016-06-21  1:44   ` Thiago Jung Bauermann
  0 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Michael Ellerman, x86, kexec, linux-kernel, Eric Biederman,
	Thiago Jung Bauermann, Mimi Zohar, Dave Young, Eric Richter

The buffer hand-over mechanism allows the currently running kernel to pass
data to kernel that will be kexec'd via a kexec segment. The second kernel
can check whether the previous kernel sent data and retrieve it.

This is the architecture-specific part.

Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/kexec.h       |  9 +++++
 arch/powerpc/kernel/kexec_elf_64.c     | 44 +++++++++++++++++++++++
 arch/powerpc/kernel/machine_kexec_64.c | 64 ++++++++++++++++++++++++++++++++++
 3 files changed, 117 insertions(+)

diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
index a46f5f45570c..9b1ff59bc188 100644
--- a/arch/powerpc/include/asm/kexec.h
+++ b/arch/powerpc/include/asm/kexec.h
@@ -55,6 +55,15 @@ typedef void (*crash_shutdown_t)(void);
 
 #ifdef CONFIG_KEXEC
 
+#ifdef CONFIG_KEXEC_FILE
+#define ARCH_HAS_KIMAGE_ARCH
+
+struct kimage_arch {
+	phys_addr_t handover_buffer_addr;
+	unsigned long handover_buffer_size;
+};
+#endif
+
 /*
  * This function is responsible for capturing register states if coming
  * via panic or invoking dump using sysrq-trigger.
diff --git a/arch/powerpc/kernel/kexec_elf_64.c b/arch/powerpc/kernel/kexec_elf_64.c
index 4e71595300ed..5d2b7036fee7 100644
--- a/arch/powerpc/kernel/kexec_elf_64.c
+++ b/arch/powerpc/kernel/kexec_elf_64.c
@@ -96,6 +96,46 @@ static int elf64_probe(const char *buf, unsigned long len)
 	return elf_check_arch(&ehdr)? 0 : -ENOEXEC;
 }
 
+static int setup_handover_buffer(struct kimage *image, void *fdt,
+				 int chosen_node)
+{
+	int ret;
+
+	if (image->arch.handover_buffer_addr) {
+		ret = fdt_setprop_u64(fdt, chosen_node,
+				      "linux,kexec-handover-buffer-start",
+				      image->arch.handover_buffer_addr);
+		if (ret < 0) {
+			pr_err("Error setting up the new device tree.\n");
+			return -EINVAL;
+		}
+
+		/* -end is the first address after the buffer. */
+		ret = fdt_setprop_u64(fdt, chosen_node,
+				      "linux,kexec-handover-buffer-end",
+				      image->arch.handover_buffer_addr +
+				      image->arch.handover_buffer_size);
+		if (ret < 0) {
+			pr_err("Error setting up the new device tree.\n");
+			return -EINVAL;
+		}
+
+		ret = fdt_add_mem_rsv(fdt, image->arch.handover_buffer_addr,
+				      image->arch.handover_buffer_size);
+		if (ret) {
+			pr_err("Error reserving kexec handover buffer: %s\n",
+			       fdt_strerror(ret));
+			return -EINVAL;
+		}
+
+		pr_debug("kexec handover buffer at 0x%llx, size = 0x%lx\n",
+			 image->arch.handover_buffer_addr,
+			 image->arch.handover_buffer_size);
+	}
+
+	return 0;
+}
+
 static bool find_debug_console(void *fdt, int chosen_node)
 {
 	int len;
@@ -494,6 +534,10 @@ void *elf64_load(struct kimage *image, char *kernel_buf,
 		}
 	}
 
+	ret = setup_handover_buffer(image, fdt, chosen_node);
+	if (ret)
+		goto out;
+
 	ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0);
 	if (ret) {
 		pr_err("Error setting up the new device tree.\n");
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index 43e8185ab6f7..c582abf726f5 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -19,6 +19,7 @@
 #include <linux/cpu.h>
 #include <linux/hardirq.h>
 #include <linux/memblock.h>
+#include <linux/libfdt.h>
 
 #include <asm/page.h>
 #include <asm/current.h>
@@ -481,6 +482,69 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
 	return image->fops->cleanup(image->image_loader_data);
 }
 
+bool kexec_can_hand_over_buffer(void)
+{
+	return true;
+}
+
+int arch_kexec_add_handover_buffer(struct kimage *image,
+				   unsigned long load_addr, unsigned long size)
+{
+	image->arch.handover_buffer_addr = load_addr;
+	image->arch.handover_buffer_size = size;
+
+	return 0;
+}
+
+int kexec_get_handover_buffer(void **addr, unsigned long *size)
+{
+	int chosen_node;
+	int startsz, endsz;
+	const void *startp, *endp;
+	unsigned long start_addr, end_addr;
+
+	chosen_node = fdt_path_offset(initial_boot_params, "/chosen");
+	if (chosen_node < 0) {
+		pr_err("Malformed device tree: /chosen not found.\n");
+		return -EINVAL;
+	}
+
+	startp = of_get_flat_dt_prop(chosen_node,
+				     "linux,kexec-handover-buffer-start",
+				     &startsz);
+	endp = of_get_flat_dt_prop(chosen_node,
+				   "linux,kexec-handover-buffer-end",
+				   &endsz);
+	if (!startp || !endp) {
+		pr_debug("kexec handover buffer not found in the device tree.\n");
+		return -ENOENT;
+	}
+
+	start_addr = of_read_number(startp, startsz/4);
+	end_addr = of_read_number(endp, endsz/4);
+
+	*addr =  __va(start_addr);
+	/* -end is the first address after the buffer. */
+	*size = end_addr - start_addr;
+
+	pr_debug("kexec handover buffer at %p, size = %lu\n", *addr, *size);
+
+	return 0;
+}
+
+int kexec_free_handover_buffer(void)
+{
+	int ret;
+	void *addr;
+	unsigned long size;
+
+	ret = kexec_get_handover_buffer(&addr, &size);
+	if (ret)
+		return ret;
+
+	return memblock_free((phys_addr_t) addr, size);
+}
+
 /**
  * arch_kexec_walk_mem - call func(data) for each unreserved memory block
  * @image_type:	kimage.type
-- 
1.9.1


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 3/6] kexec_file: Allow skipping checksum calculation for some segments.
  2016-06-21  1:44 ` Thiago Jung Bauermann
@ 2016-06-21  1:44   ` Thiago Jung Bauermann
  -1 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: kexec, x86, linux-kernel, Eric Biederman, Dave Young,
	Michael Ellerman, Mimi Zohar, Eric Richter,
	Thiago Jung Bauermann

Adds checksum argument to kexec_add_buffer specifying whether the given
segment should be part of the checksum calculation.

The next patch will add a way to update segments after a kimage is loaded.
Segments that will be updated in this way should not be checksummed,
otherwise they will cause the purgatory checksum verification to fail
when the machine is rebooted.

As a bonus, we don't need to special-case the purgatory segment anymore
to avoid checksumming it.

Adjust call sites for the new argument.

Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
 arch/powerpc/kernel/kexec_elf_64.c |  6 +++---
 arch/x86/kernel/crash.c            |  4 ++--
 arch/x86/kernel/kexec-bzimage64.c  |  6 +++---
 include/linux/kexec.h              |  7 +++++--
 kernel/kexec_file.c                | 22 +++++++++++-----------
 5 files changed, 24 insertions(+), 21 deletions(-)

diff --git a/arch/powerpc/kernel/kexec_elf_64.c b/arch/powerpc/kernel/kexec_elf_64.c
index 5d2b7036fee7..abbad484d7b2 100644
--- a/arch/powerpc/kernel/kexec_elf_64.c
+++ b/arch/powerpc/kernel/kexec_elf_64.c
@@ -311,7 +311,7 @@ static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr,
 				       (char *) elf_info->buffer + phdr->p_offset,
 				       size, phdr->p_memsz, phdr->p_align,
 				       phdr->p_paddr + base, ppc64_rma_size,
-				       false, &load_addr);
+				       false, true, &load_addr);
 		if (ret)
 			goto out;
 
@@ -487,7 +487,7 @@ void *elf64_load(struct kimage *image, char *kernel_buf,
 	if (initrd != NULL) {
 		ret = kexec_add_buffer(image, initrd, initrd_len, initrd_len,
 				       PAGE_SIZE, 0, ppc64_rma_size, false,
-				       &initrd_load_addr);
+				       true, &initrd_load_addr);
 		if (ret)
 			goto out;
 
@@ -564,7 +564,7 @@ void *elf64_load(struct kimage *image, char *kernel_buf,
 	fdt_pack(fdt);
 
 	ret = kexec_add_buffer(image, fdt, fdt_size, fdt_size, PAGE_SIZE, 0,
-			       ppc64_rma_size, true, &fdt_load_addr);
+			       ppc64_rma_size, true, true, &fdt_load_addr);
 	if (ret)
 		goto out;
 
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 9ef978d69c22..c8b16f2ca321 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -643,7 +643,7 @@ int crash_load_segments(struct kimage *image)
 		 */
 		ret = kexec_add_buffer(image, (char *)&crash_zero_bytes,
 				       sizeof(crash_zero_bytes), src_sz,
-				       PAGE_SIZE, 0, -1, 0,
+				       PAGE_SIZE, 0, -1, false, true,
 				       &image->arch.backup_load_addr);
 		if (ret)
 			return ret;
@@ -660,7 +660,7 @@ int crash_load_segments(struct kimage *image)
 	image->arch.elf_headers_sz = elf_sz;
 
 	ret = kexec_add_buffer(image, (char *)elf_addr, elf_sz, elf_sz,
-			ELF_CORE_HEADER_ALIGN, 0, -1, 0,
+			ELF_CORE_HEADER_ALIGN, 0, -1, false, true,
 			&image->arch.elf_load_addr);
 	if (ret) {
 		vfree((void *)image->arch.elf_headers);
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index f2356bda2b05..f9016be44da6 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -420,7 +420,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 
 	ret = kexec_add_buffer(image, (char *)params, params_misc_sz,
 			       params_misc_sz, 16, MIN_BOOTPARAM_ADDR,
-			       ULONG_MAX, 1, &bootparam_load_addr);
+			       ULONG_MAX, true, true, &bootparam_load_addr);
 	if (ret)
 		goto out_free_params;
 	pr_debug("Loaded boot_param, command line and misc at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
@@ -434,7 +434,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 
 	ret = kexec_add_buffer(image, kernel_buf,
 			       kernel_bufsz, kernel_memsz, kernel_align,
-			       MIN_KERNEL_LOAD_ADDR, ULONG_MAX, 1,
+			       MIN_KERNEL_LOAD_ADDR, ULONG_MAX, true, true,
 			       &kernel_load_addr);
 	if (ret)
 		goto out_free_params;
@@ -446,7 +446,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 	if (initrd) {
 		ret = kexec_add_buffer(image, initrd, initrd_len, initrd_len,
 				       PAGE_SIZE, MIN_INITRD_LOAD_ADDR,
-				       ULONG_MAX, 1, &initrd_load_addr);
+				       ULONG_MAX, true, true, &initrd_load_addr);
 		if (ret)
 			goto out_free_params;
 
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 72db95c623b3..131b1fc7820e 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -98,6 +98,9 @@ struct kexec_segment {
 	size_t bufsz;
 	unsigned long mem;
 	size_t memsz;
+
+	/* Whether this segment is part of the checksum calculation. */
+	bool do_checksum;
 };
 
 #ifdef CONFIG_COMPAT
@@ -217,7 +220,7 @@ int kexec_locate_mem_hole(struct kimage *image, unsigned long size,
 extern int kexec_add_buffer(struct kimage *image, char *buffer,
 			    unsigned long bufsz, unsigned long memsz,
 			    unsigned long buf_align, unsigned long buf_min,
-			    unsigned long buf_max, bool top_down,
+			    unsigned long buf_max, bool top_down, bool checksum,
 			    unsigned long *load_addr);
 extern struct page *kimage_alloc_control_pages(struct kimage *image,
 						unsigned int order);
@@ -334,7 +337,7 @@ int kexec_add_handover_buffer(struct kimage *image, void *buffer,
 			      unsigned long bufsz, unsigned long memsz,
 			      unsigned long buf_align, unsigned long buf_min,
 			      unsigned long buf_max, bool top_down,
-			      unsigned long *load_addr);
+			      bool checksum, unsigned long *load_addr);
 int __weak kexec_get_handover_buffer(void **addr, unsigned long *size);
 int __weak kexec_free_handover_buffer(void);
 #else
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index d6ba702654f5..3aa829a78f50 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -146,6 +146,7 @@ int __weak arch_kexec_add_handover_buffer(struct kimage *image,
  * @buf_min:	Minimum address where buffer can be placed.
  * @buf_max:	Maximum address where buffer can be placed.
  * @top_down:	Find the highest available memory position for the buffer?
+ * @checksum:	Should this buffer checksum be verified by the purgatory?
  * @load_addr:	On successful return, set to the physical memory address of the
  * 		buffer in the next kernel.
  *
@@ -157,7 +158,7 @@ int kexec_add_handover_buffer(struct kimage *image, void *buffer,
 			      unsigned long bufsz, unsigned long memsz,
 			      unsigned long buf_align, unsigned long buf_min,
 			      unsigned long buf_max, bool top_down,
-			      unsigned long *load_addr)
+			      bool checksum, unsigned long *load_addr)
 {
 	int ret;
 
@@ -165,7 +166,7 @@ int kexec_add_handover_buffer(struct kimage *image, void *buffer,
 		return -ENOTSUPP;
 
 	ret = kexec_add_buffer(image, buffer, bufsz, memsz, buf_align, buf_min,
-			       buf_max, top_down, load_addr);
+			       buf_max, top_down, checksum, load_addr);
 	if (ret)
 		return ret;
 
@@ -590,7 +591,7 @@ int kexec_locate_mem_hole(struct kimage *image, unsigned long size,
 int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,
 		     unsigned long memsz, unsigned long buf_align,
 		     unsigned long buf_min, unsigned long buf_max,
-		     bool top_down, unsigned long *load_addr)
+		     bool top_down, bool checksum, unsigned long *load_addr)
 {
 
 	struct kexec_segment *ksegment;
@@ -630,6 +631,7 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,
 	ksegment->bufsz = bufsz;
 	ksegment->mem = addr;
 	ksegment->memsz = size;
+	ksegment->do_checksum = checksum;
 	image->nr_segments++;
 	*load_addr = ksegment->mem;
 	return 0;
@@ -645,7 +647,6 @@ static int kexec_calculate_store_digests(struct kimage *image)
 	char *digest;
 	void *zero_buf;
 	struct kexec_sha_region *sha_regions;
-	struct purgatory_info *pi = &image->purgatory_info;
 
 	zero_buf = __va(page_to_pfn(ZERO_PAGE(0)) << PAGE_SHIFT);
 	zero_buf_sz = PAGE_SIZE;
@@ -685,11 +686,7 @@ static int kexec_calculate_store_digests(struct kimage *image)
 		struct kexec_segment *ksegment;
 
 		ksegment = &image->segment[i];
-		/*
-		 * Skip purgatory as it will be modified once we put digest
-		 * info in purgatory.
-		 */
-		if (ksegment->kbuf == pi->purgatory_buf)
+		if (!ksegment->do_checksum)
 			continue;
 
 		ret = crypto_shash_update(desc, ksegment->kbuf,
@@ -866,9 +863,12 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min,
 	if (buf_align < bss_align)
 		buf_align = bss_align;
 
-	/* Add buffer to segment list */
+	/*
+	 * Add buffer to segment list. Don't checksum the segment as
+	 * it will be modified once we put digest info in purgatory.
+	 */
 	ret = kexec_add_buffer(image, purgatory_buf, buf_sz, memsz,
-				buf_align, min, max, top_down,
+				buf_align, min, max, top_down, false,
 				&pi->purgatory_load_addr);
 	if (ret)
 		goto out;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 3/6] kexec_file: Allow skipping checksum calculation for some segments.
@ 2016-06-21  1:44   ` Thiago Jung Bauermann
  0 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Michael Ellerman, x86, kexec, linux-kernel, Eric Biederman,
	Thiago Jung Bauermann, Mimi Zohar, Dave Young, Eric Richter

Adds checksum argument to kexec_add_buffer specifying whether the given
segment should be part of the checksum calculation.

The next patch will add a way to update segments after a kimage is loaded.
Segments that will be updated in this way should not be checksummed,
otherwise they will cause the purgatory checksum verification to fail
when the machine is rebooted.

As a bonus, we don't need to special-case the purgatory segment anymore
to avoid checksumming it.

Adjust call sites for the new argument.

Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
 arch/powerpc/kernel/kexec_elf_64.c |  6 +++---
 arch/x86/kernel/crash.c            |  4 ++--
 arch/x86/kernel/kexec-bzimage64.c  |  6 +++---
 include/linux/kexec.h              |  7 +++++--
 kernel/kexec_file.c                | 22 +++++++++++-----------
 5 files changed, 24 insertions(+), 21 deletions(-)

diff --git a/arch/powerpc/kernel/kexec_elf_64.c b/arch/powerpc/kernel/kexec_elf_64.c
index 5d2b7036fee7..abbad484d7b2 100644
--- a/arch/powerpc/kernel/kexec_elf_64.c
+++ b/arch/powerpc/kernel/kexec_elf_64.c
@@ -311,7 +311,7 @@ static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr,
 				       (char *) elf_info->buffer + phdr->p_offset,
 				       size, phdr->p_memsz, phdr->p_align,
 				       phdr->p_paddr + base, ppc64_rma_size,
-				       false, &load_addr);
+				       false, true, &load_addr);
 		if (ret)
 			goto out;
 
@@ -487,7 +487,7 @@ void *elf64_load(struct kimage *image, char *kernel_buf,
 	if (initrd != NULL) {
 		ret = kexec_add_buffer(image, initrd, initrd_len, initrd_len,
 				       PAGE_SIZE, 0, ppc64_rma_size, false,
-				       &initrd_load_addr);
+				       true, &initrd_load_addr);
 		if (ret)
 			goto out;
 
@@ -564,7 +564,7 @@ void *elf64_load(struct kimage *image, char *kernel_buf,
 	fdt_pack(fdt);
 
 	ret = kexec_add_buffer(image, fdt, fdt_size, fdt_size, PAGE_SIZE, 0,
-			       ppc64_rma_size, true, &fdt_load_addr);
+			       ppc64_rma_size, true, true, &fdt_load_addr);
 	if (ret)
 		goto out;
 
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 9ef978d69c22..c8b16f2ca321 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -643,7 +643,7 @@ int crash_load_segments(struct kimage *image)
 		 */
 		ret = kexec_add_buffer(image, (char *)&crash_zero_bytes,
 				       sizeof(crash_zero_bytes), src_sz,
-				       PAGE_SIZE, 0, -1, 0,
+				       PAGE_SIZE, 0, -1, false, true,
 				       &image->arch.backup_load_addr);
 		if (ret)
 			return ret;
@@ -660,7 +660,7 @@ int crash_load_segments(struct kimage *image)
 	image->arch.elf_headers_sz = elf_sz;
 
 	ret = kexec_add_buffer(image, (char *)elf_addr, elf_sz, elf_sz,
-			ELF_CORE_HEADER_ALIGN, 0, -1, 0,
+			ELF_CORE_HEADER_ALIGN, 0, -1, false, true,
 			&image->arch.elf_load_addr);
 	if (ret) {
 		vfree((void *)image->arch.elf_headers);
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index f2356bda2b05..f9016be44da6 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -420,7 +420,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 
 	ret = kexec_add_buffer(image, (char *)params, params_misc_sz,
 			       params_misc_sz, 16, MIN_BOOTPARAM_ADDR,
-			       ULONG_MAX, 1, &bootparam_load_addr);
+			       ULONG_MAX, true, true, &bootparam_load_addr);
 	if (ret)
 		goto out_free_params;
 	pr_debug("Loaded boot_param, command line and misc at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
@@ -434,7 +434,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 
 	ret = kexec_add_buffer(image, kernel_buf,
 			       kernel_bufsz, kernel_memsz, kernel_align,
-			       MIN_KERNEL_LOAD_ADDR, ULONG_MAX, 1,
+			       MIN_KERNEL_LOAD_ADDR, ULONG_MAX, true, true,
 			       &kernel_load_addr);
 	if (ret)
 		goto out_free_params;
@@ -446,7 +446,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 	if (initrd) {
 		ret = kexec_add_buffer(image, initrd, initrd_len, initrd_len,
 				       PAGE_SIZE, MIN_INITRD_LOAD_ADDR,
-				       ULONG_MAX, 1, &initrd_load_addr);
+				       ULONG_MAX, true, true, &initrd_load_addr);
 		if (ret)
 			goto out_free_params;
 
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 72db95c623b3..131b1fc7820e 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -98,6 +98,9 @@ struct kexec_segment {
 	size_t bufsz;
 	unsigned long mem;
 	size_t memsz;
+
+	/* Whether this segment is part of the checksum calculation. */
+	bool do_checksum;
 };
 
 #ifdef CONFIG_COMPAT
@@ -217,7 +220,7 @@ int kexec_locate_mem_hole(struct kimage *image, unsigned long size,
 extern int kexec_add_buffer(struct kimage *image, char *buffer,
 			    unsigned long bufsz, unsigned long memsz,
 			    unsigned long buf_align, unsigned long buf_min,
-			    unsigned long buf_max, bool top_down,
+			    unsigned long buf_max, bool top_down, bool checksum,
 			    unsigned long *load_addr);
 extern struct page *kimage_alloc_control_pages(struct kimage *image,
 						unsigned int order);
@@ -334,7 +337,7 @@ int kexec_add_handover_buffer(struct kimage *image, void *buffer,
 			      unsigned long bufsz, unsigned long memsz,
 			      unsigned long buf_align, unsigned long buf_min,
 			      unsigned long buf_max, bool top_down,
-			      unsigned long *load_addr);
+			      bool checksum, unsigned long *load_addr);
 int __weak kexec_get_handover_buffer(void **addr, unsigned long *size);
 int __weak kexec_free_handover_buffer(void);
 #else
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index d6ba702654f5..3aa829a78f50 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -146,6 +146,7 @@ int __weak arch_kexec_add_handover_buffer(struct kimage *image,
  * @buf_min:	Minimum address where buffer can be placed.
  * @buf_max:	Maximum address where buffer can be placed.
  * @top_down:	Find the highest available memory position for the buffer?
+ * @checksum:	Should this buffer checksum be verified by the purgatory?
  * @load_addr:	On successful return, set to the physical memory address of the
  * 		buffer in the next kernel.
  *
@@ -157,7 +158,7 @@ int kexec_add_handover_buffer(struct kimage *image, void *buffer,
 			      unsigned long bufsz, unsigned long memsz,
 			      unsigned long buf_align, unsigned long buf_min,
 			      unsigned long buf_max, bool top_down,
-			      unsigned long *load_addr)
+			      bool checksum, unsigned long *load_addr)
 {
 	int ret;
 
@@ -165,7 +166,7 @@ int kexec_add_handover_buffer(struct kimage *image, void *buffer,
 		return -ENOTSUPP;
 
 	ret = kexec_add_buffer(image, buffer, bufsz, memsz, buf_align, buf_min,
-			       buf_max, top_down, load_addr);
+			       buf_max, top_down, checksum, load_addr);
 	if (ret)
 		return ret;
 
@@ -590,7 +591,7 @@ int kexec_locate_mem_hole(struct kimage *image, unsigned long size,
 int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,
 		     unsigned long memsz, unsigned long buf_align,
 		     unsigned long buf_min, unsigned long buf_max,
-		     bool top_down, unsigned long *load_addr)
+		     bool top_down, bool checksum, unsigned long *load_addr)
 {
 
 	struct kexec_segment *ksegment;
@@ -630,6 +631,7 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,
 	ksegment->bufsz = bufsz;
 	ksegment->mem = addr;
 	ksegment->memsz = size;
+	ksegment->do_checksum = checksum;
 	image->nr_segments++;
 	*load_addr = ksegment->mem;
 	return 0;
@@ -645,7 +647,6 @@ static int kexec_calculate_store_digests(struct kimage *image)
 	char *digest;
 	void *zero_buf;
 	struct kexec_sha_region *sha_regions;
-	struct purgatory_info *pi = &image->purgatory_info;
 
 	zero_buf = __va(page_to_pfn(ZERO_PAGE(0)) << PAGE_SHIFT);
 	zero_buf_sz = PAGE_SIZE;
@@ -685,11 +686,7 @@ static int kexec_calculate_store_digests(struct kimage *image)
 		struct kexec_segment *ksegment;
 
 		ksegment = &image->segment[i];
-		/*
-		 * Skip purgatory as it will be modified once we put digest
-		 * info in purgatory.
-		 */
-		if (ksegment->kbuf == pi->purgatory_buf)
+		if (!ksegment->do_checksum)
 			continue;
 
 		ret = crypto_shash_update(desc, ksegment->kbuf,
@@ -866,9 +863,12 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min,
 	if (buf_align < bss_align)
 		buf_align = bss_align;
 
-	/* Add buffer to segment list */
+	/*
+	 * Add buffer to segment list. Don't checksum the segment as
+	 * it will be modified once we put digest info in purgatory.
+	 */
 	ret = kexec_add_buffer(image, purgatory_buf, buf_sz, memsz,
-				buf_align, min, max, top_down,
+				buf_align, min, max, top_down, false,
 				&pi->purgatory_load_addr);
 	if (ret)
 		goto out;
-- 
1.9.1


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 4/6] kexec_file: Add mechanism to update kexec segments.
  2016-06-21  1:44 ` Thiago Jung Bauermann
@ 2016-06-21  1:44   ` Thiago Jung Bauermann
  -1 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: kexec, x86, linux-kernel, Eric Biederman, Dave Young,
	Michael Ellerman, Mimi Zohar, Eric Richter,
	Thiago Jung Bauermann

kexec_update_segment allows a given segment in kexec_image to have
its contents updated. This is useful if the current kernel wants to
send information to the next kernel that is up-to-date at the time of
reboot.

Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
 include/linux/kexec.h |  2 ++
 kernel/kexec_core.c   | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/kexec_file.c   |  1 +
 3 files changed, 91 insertions(+)

diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 131b1fc7820e..14d4ac070a8c 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -222,6 +222,8 @@ extern int kexec_add_buffer(struct kimage *image, char *buffer,
 			    unsigned long buf_align, unsigned long buf_min,
 			    unsigned long buf_max, bool top_down, bool checksum,
 			    unsigned long *load_addr);
+int kexec_update_segment(const char *buffer, unsigned long bufsz,
+			 unsigned long load_addr, unsigned long memsz);
 extern struct page *kimage_alloc_control_pages(struct kimage *image,
 						unsigned int order);
 extern int kexec_load_purgatory(struct kimage *image, unsigned long min,
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 56b3ed0927b0..8781d3e4479d 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -700,6 +700,94 @@ static struct page *kimage_alloc_page(struct kimage *image,
 	return page;
 }
 
+/**
+ * kexec_update_segment - update the contents of a kimage segment
+ * @buffer:	New contents of the segment.
+ * @bufsz:	@buffer size.
+ * @load_addr:	Segment's physical address in the next kernel.
+ * @memsz:	Segment size.
+ *
+ * This function assumes kexec_mutex is held.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int kexec_update_segment(const char *buffer, unsigned long bufsz,
+			 unsigned long load_addr, unsigned long memsz)
+{
+	int i;
+	unsigned long entry;
+	unsigned long *ptr = NULL;
+	void *dest = NULL;
+
+	for (i = 0; i < kexec_image->nr_segments; i++)
+		/* We only support updating whole segments. */
+		if (load_addr == kexec_image->segment[i].mem &&
+		    memsz == kexec_image->segment[i].memsz) {
+			if (kexec_image->segment[i].do_checksum) {
+				pr_err("Trying to update non-modifiable segment.\n");
+				return -EINVAL;
+			}
+
+			break;
+		}
+	if (i == kexec_image->nr_segments) {
+		pr_err("Couldn't find segment to update: 0x%lx, size 0x%lx\n",
+		       load_addr, memsz);
+		return -EINVAL;
+	}
+
+	for (entry = kexec_image->head; !(entry & IND_DONE) && memsz;
+	     entry = *ptr++) {
+		void *addr = (void *) (entry & PAGE_MASK);
+
+		switch (entry & IND_FLAGS) {
+		case IND_DESTINATION:
+			dest = addr;
+			break;
+		case IND_INDIRECTION:
+			ptr = __va(addr);
+			break;
+		case IND_SOURCE:
+			/* Shouldn't happen, but verify just to be safe. */
+			if (dest == NULL) {
+				pr_err("Invalid kexec entries list.");
+				return -EINVAL;
+			}
+
+			if (dest == (void *) load_addr) {
+				struct page *page;
+				char *ptr;
+				size_t uchunk, mchunk;
+
+				page = kmap_to_page(addr);
+
+				ptr = kmap(page);
+				ptr += load_addr & ~PAGE_MASK;
+				mchunk = min_t(size_t, memsz,
+					       PAGE_SIZE - (load_addr & ~PAGE_MASK));
+				uchunk = min(bufsz, mchunk);
+				memcpy(ptr, buffer, uchunk);
+
+				kunmap(page);
+
+				bufsz -= uchunk;
+				load_addr += mchunk;
+				buffer += mchunk;
+				memsz -= mchunk;
+			}
+			dest += PAGE_SIZE;
+		}
+
+		/* Shouldn't happen, but verify just to be safe. */
+		if (ptr == NULL) {
+			pr_err("Invalid kexec entries list.");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int kimage_load_normal_segment(struct kimage *image,
 					 struct kexec_segment *segment)
 {
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 3aa829a78f50..79d09a7784d8 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -15,6 +15,7 @@
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/slab.h>
+#include <linux/highmem.h>
 #include <linux/kexec.h>
 #include <linux/mutex.h>
 #include <linux/list.h>
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 4/6] kexec_file: Add mechanism to update kexec segments.
@ 2016-06-21  1:44   ` Thiago Jung Bauermann
  0 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Michael Ellerman, x86, kexec, linux-kernel, Eric Biederman,
	Thiago Jung Bauermann, Mimi Zohar, Dave Young, Eric Richter

kexec_update_segment allows a given segment in kexec_image to have
its contents updated. This is useful if the current kernel wants to
send information to the next kernel that is up-to-date at the time of
reboot.

Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
 include/linux/kexec.h |  2 ++
 kernel/kexec_core.c   | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/kexec_file.c   |  1 +
 3 files changed, 91 insertions(+)

diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 131b1fc7820e..14d4ac070a8c 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -222,6 +222,8 @@ extern int kexec_add_buffer(struct kimage *image, char *buffer,
 			    unsigned long buf_align, unsigned long buf_min,
 			    unsigned long buf_max, bool top_down, bool checksum,
 			    unsigned long *load_addr);
+int kexec_update_segment(const char *buffer, unsigned long bufsz,
+			 unsigned long load_addr, unsigned long memsz);
 extern struct page *kimage_alloc_control_pages(struct kimage *image,
 						unsigned int order);
 extern int kexec_load_purgatory(struct kimage *image, unsigned long min,
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 56b3ed0927b0..8781d3e4479d 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -700,6 +700,94 @@ static struct page *kimage_alloc_page(struct kimage *image,
 	return page;
 }
 
+/**
+ * kexec_update_segment - update the contents of a kimage segment
+ * @buffer:	New contents of the segment.
+ * @bufsz:	@buffer size.
+ * @load_addr:	Segment's physical address in the next kernel.
+ * @memsz:	Segment size.
+ *
+ * This function assumes kexec_mutex is held.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int kexec_update_segment(const char *buffer, unsigned long bufsz,
+			 unsigned long load_addr, unsigned long memsz)
+{
+	int i;
+	unsigned long entry;
+	unsigned long *ptr = NULL;
+	void *dest = NULL;
+
+	for (i = 0; i < kexec_image->nr_segments; i++)
+		/* We only support updating whole segments. */
+		if (load_addr == kexec_image->segment[i].mem &&
+		    memsz == kexec_image->segment[i].memsz) {
+			if (kexec_image->segment[i].do_checksum) {
+				pr_err("Trying to update non-modifiable segment.\n");
+				return -EINVAL;
+			}
+
+			break;
+		}
+	if (i == kexec_image->nr_segments) {
+		pr_err("Couldn't find segment to update: 0x%lx, size 0x%lx\n",
+		       load_addr, memsz);
+		return -EINVAL;
+	}
+
+	for (entry = kexec_image->head; !(entry & IND_DONE) && memsz;
+	     entry = *ptr++) {
+		void *addr = (void *) (entry & PAGE_MASK);
+
+		switch (entry & IND_FLAGS) {
+		case IND_DESTINATION:
+			dest = addr;
+			break;
+		case IND_INDIRECTION:
+			ptr = __va(addr);
+			break;
+		case IND_SOURCE:
+			/* Shouldn't happen, but verify just to be safe. */
+			if (dest == NULL) {
+				pr_err("Invalid kexec entries list.");
+				return -EINVAL;
+			}
+
+			if (dest == (void *) load_addr) {
+				struct page *page;
+				char *ptr;
+				size_t uchunk, mchunk;
+
+				page = kmap_to_page(addr);
+
+				ptr = kmap(page);
+				ptr += load_addr & ~PAGE_MASK;
+				mchunk = min_t(size_t, memsz,
+					       PAGE_SIZE - (load_addr & ~PAGE_MASK));
+				uchunk = min(bufsz, mchunk);
+				memcpy(ptr, buffer, uchunk);
+
+				kunmap(page);
+
+				bufsz -= uchunk;
+				load_addr += mchunk;
+				buffer += mchunk;
+				memsz -= mchunk;
+			}
+			dest += PAGE_SIZE;
+		}
+
+		/* Shouldn't happen, but verify just to be safe. */
+		if (ptr == NULL) {
+			pr_err("Invalid kexec entries list.");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int kimage_load_normal_segment(struct kimage *image,
 					 struct kexec_segment *segment)
 {
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 3aa829a78f50..79d09a7784d8 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -15,6 +15,7 @@
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/slab.h>
+#include <linux/highmem.h>
 #include <linux/kexec.h>
 #include <linux/mutex.h>
 #include <linux/list.h>
-- 
1.9.1


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 5/6] kexec: Share logic to copy segment page contents.
  2016-06-21  1:44 ` Thiago Jung Bauermann
@ 2016-06-21  1:44   ` Thiago Jung Bauermann
  -1 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: kexec, x86, linux-kernel, Eric Biederman, Dave Young,
	Michael Ellerman, Mimi Zohar, Eric Richter,
	Thiago Jung Bauermann

Make kimage_load_normal_segment and kexec_update_segment share code
which they currently duplicate.

Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
 kernel/kexec_core.c | 159 +++++++++++++++++++++++++++++++---------------------
 1 file changed, 95 insertions(+), 64 deletions(-)

diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 8781d3e4479d..281d8b961fb4 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -700,6 +700,65 @@ static struct page *kimage_alloc_page(struct kimage *image,
 	return page;
 }
 
+struct kimage_update_buffer_state {
+	/* Destination memory address currently being copied to. */
+	unsigned long maddr;
+
+	/* Bytes in buffer still left to copy. */
+	size_t ubytes;
+
+	/* Bytes in memory still left to copy. */
+	size_t mbytes;
+
+	/* If true, copy from kbuf. */
+	bool from_kernel;
+
+	/* Clear pages before copying? */
+	bool clear_pages;
+
+	/* Buffer position to continue copying from. */
+	const unsigned char *kbuf;
+	const unsigned char __user *buf;
+};
+
+static int kimage_update_page(struct page *page,
+			      struct kimage_update_buffer_state *state)
+{
+	char *ptr;
+	int result = 0;
+	size_t uchunk, mchunk;
+
+	ptr = kmap(page);
+
+	/* Start with a clear page */
+	if (state->clear_pages)
+		clear_page(ptr);
+
+	ptr += state->maddr & ~PAGE_MASK;
+	mchunk = min_t(size_t, state->mbytes,
+		       PAGE_SIZE - (state->maddr & ~PAGE_MASK));
+	uchunk = min(state->ubytes, mchunk);
+
+	if (state->from_kernel)
+		memcpy(ptr, state->kbuf, uchunk);
+	else
+		result = copy_from_user(ptr, state->buf, uchunk);
+
+	kunmap(page);
+	if (result)
+		return -EFAULT;
+
+	state->ubytes -= uchunk;
+	state->maddr += mchunk;
+	if (state->from_kernel)
+		state->kbuf += mchunk;
+	else
+		state->buf += mchunk;
+	state->mbytes -= mchunk;
+
+	return 0;
+}
+
 /**
  * kexec_update_segment - update the contents of a kimage segment
  * @buffer:	New contents of the segment.
@@ -718,6 +777,7 @@ int kexec_update_segment(const char *buffer, unsigned long bufsz,
 	unsigned long entry;
 	unsigned long *ptr = NULL;
 	void *dest = NULL;
+	struct kimage_update_buffer_state state;
 
 	for (i = 0; i < kexec_image->nr_segments; i++)
 		/* We only support updating whole segments. */
@@ -736,8 +796,15 @@ int kexec_update_segment(const char *buffer, unsigned long bufsz,
 		return -EINVAL;
 	}
 
-	for (entry = kexec_image->head; !(entry & IND_DONE) && memsz;
-	     entry = *ptr++) {
+	state.maddr = load_addr;
+	state.ubytes = bufsz;
+	state.mbytes = memsz;
+	state.kbuf = buffer;
+	state.from_kernel = true;
+	state.clear_pages = false;
+
+	for (entry = kexec_image->head; !(entry & IND_DONE) &&
+					state.mbytes; entry = *ptr++) {
 		void *addr = (void *) (entry & PAGE_MASK);
 
 		switch (entry & IND_FLAGS) {
@@ -754,26 +821,13 @@ int kexec_update_segment(const char *buffer, unsigned long bufsz,
 				return -EINVAL;
 			}
 
-			if (dest == (void *) load_addr) {
-				struct page *page;
-				char *ptr;
-				size_t uchunk, mchunk;
-
-				page = kmap_to_page(addr);
-
-				ptr = kmap(page);
-				ptr += load_addr & ~PAGE_MASK;
-				mchunk = min_t(size_t, memsz,
-					       PAGE_SIZE - (load_addr & ~PAGE_MASK));
-				uchunk = min(bufsz, mchunk);
-				memcpy(ptr, buffer, uchunk);
-
-				kunmap(page);
+			if (dest == (void *) state.maddr) {
+				int ret;
 
-				bufsz -= uchunk;
-				load_addr += mchunk;
-				buffer += mchunk;
-				memsz -= mchunk;
+				ret = kimage_update_page(kmap_to_page(addr),
+							 &state);
+				if (ret)
+					return ret;
 			}
 			dest += PAGE_SIZE;
 		}
@@ -791,31 +845,30 @@ int kexec_update_segment(const char *buffer, unsigned long bufsz,
 static int kimage_load_normal_segment(struct kimage *image,
 					 struct kexec_segment *segment)
 {
-	unsigned long maddr;
-	size_t ubytes, mbytes;
-	int result;
-	unsigned char __user *buf = NULL;
-	unsigned char *kbuf = NULL;
-
-	result = 0;
-	if (image->file_mode)
-		kbuf = segment->kbuf;
-	else
-		buf = segment->buf;
-	ubytes = segment->bufsz;
-	mbytes = segment->memsz;
-	maddr = segment->mem;
+	int result = 0;
+	struct kimage_update_buffer_state state;
+
+	/* For file based kexec, source pages are in kernel memory */
+	if (image->file_mode) {
+		state.kbuf = segment->kbuf;
+		state.from_kernel = true;
+	} else {
+		state.buf = segment->buf;
+		state.from_kernel = false;
+	}
+	state.ubytes = segment->bufsz;
+	state.mbytes = segment->memsz;
+	state.maddr = segment->mem;
+	state.clear_pages = true;
 
-	result = kimage_set_destination(image, maddr);
+	result = kimage_set_destination(image, state.maddr);
 	if (result < 0)
 		goto out;
 
-	while (mbytes) {
+	while (state.mbytes) {
 		struct page *page;
-		char *ptr;
-		size_t uchunk, mchunk;
 
-		page = kimage_alloc_page(image, GFP_HIGHUSER, maddr);
+		page = kimage_alloc_page(image, GFP_HIGHUSER, state.maddr);
 		if (!page) {
 			result  = -ENOMEM;
 			goto out;
@@ -825,31 +878,9 @@ static int kimage_load_normal_segment(struct kimage *image,
 		if (result < 0)
 			goto out;
 
-		ptr = kmap(page);
-		/* Start with a clear page */
-		clear_page(ptr);
-		ptr += maddr & ~PAGE_MASK;
-		mchunk = min_t(size_t, mbytes,
-				PAGE_SIZE - (maddr & ~PAGE_MASK));
-		uchunk = min(ubytes, mchunk);
-
-		/* For file based kexec, source pages are in kernel memory */
-		if (image->file_mode)
-			memcpy(ptr, kbuf, uchunk);
-		else
-			result = copy_from_user(ptr, buf, uchunk);
-		kunmap(page);
-		if (result) {
-			result = -EFAULT;
+		result = kimage_update_page(page, &state);
+		if (result)
 			goto out;
-		}
-		ubytes -= uchunk;
-		maddr  += mchunk;
-		if (image->file_mode)
-			kbuf += mchunk;
-		else
-			buf += mchunk;
-		mbytes -= mchunk;
 	}
 out:
 	return result;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 5/6] kexec: Share logic to copy segment page contents.
@ 2016-06-21  1:44   ` Thiago Jung Bauermann
  0 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Michael Ellerman, x86, kexec, linux-kernel, Eric Biederman,
	Thiago Jung Bauermann, Mimi Zohar, Dave Young, Eric Richter

Make kimage_load_normal_segment and kexec_update_segment share code
which they currently duplicate.

Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
 kernel/kexec_core.c | 159 +++++++++++++++++++++++++++++++---------------------
 1 file changed, 95 insertions(+), 64 deletions(-)

diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 8781d3e4479d..281d8b961fb4 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -700,6 +700,65 @@ static struct page *kimage_alloc_page(struct kimage *image,
 	return page;
 }
 
+struct kimage_update_buffer_state {
+	/* Destination memory address currently being copied to. */
+	unsigned long maddr;
+
+	/* Bytes in buffer still left to copy. */
+	size_t ubytes;
+
+	/* Bytes in memory still left to copy. */
+	size_t mbytes;
+
+	/* If true, copy from kbuf. */
+	bool from_kernel;
+
+	/* Clear pages before copying? */
+	bool clear_pages;
+
+	/* Buffer position to continue copying from. */
+	const unsigned char *kbuf;
+	const unsigned char __user *buf;
+};
+
+static int kimage_update_page(struct page *page,
+			      struct kimage_update_buffer_state *state)
+{
+	char *ptr;
+	int result = 0;
+	size_t uchunk, mchunk;
+
+	ptr = kmap(page);
+
+	/* Start with a clear page */
+	if (state->clear_pages)
+		clear_page(ptr);
+
+	ptr += state->maddr & ~PAGE_MASK;
+	mchunk = min_t(size_t, state->mbytes,
+		       PAGE_SIZE - (state->maddr & ~PAGE_MASK));
+	uchunk = min(state->ubytes, mchunk);
+
+	if (state->from_kernel)
+		memcpy(ptr, state->kbuf, uchunk);
+	else
+		result = copy_from_user(ptr, state->buf, uchunk);
+
+	kunmap(page);
+	if (result)
+		return -EFAULT;
+
+	state->ubytes -= uchunk;
+	state->maddr += mchunk;
+	if (state->from_kernel)
+		state->kbuf += mchunk;
+	else
+		state->buf += mchunk;
+	state->mbytes -= mchunk;
+
+	return 0;
+}
+
 /**
  * kexec_update_segment - update the contents of a kimage segment
  * @buffer:	New contents of the segment.
@@ -718,6 +777,7 @@ int kexec_update_segment(const char *buffer, unsigned long bufsz,
 	unsigned long entry;
 	unsigned long *ptr = NULL;
 	void *dest = NULL;
+	struct kimage_update_buffer_state state;
 
 	for (i = 0; i < kexec_image->nr_segments; i++)
 		/* We only support updating whole segments. */
@@ -736,8 +796,15 @@ int kexec_update_segment(const char *buffer, unsigned long bufsz,
 		return -EINVAL;
 	}
 
-	for (entry = kexec_image->head; !(entry & IND_DONE) && memsz;
-	     entry = *ptr++) {
+	state.maddr = load_addr;
+	state.ubytes = bufsz;
+	state.mbytes = memsz;
+	state.kbuf = buffer;
+	state.from_kernel = true;
+	state.clear_pages = false;
+
+	for (entry = kexec_image->head; !(entry & IND_DONE) &&
+					state.mbytes; entry = *ptr++) {
 		void *addr = (void *) (entry & PAGE_MASK);
 
 		switch (entry & IND_FLAGS) {
@@ -754,26 +821,13 @@ int kexec_update_segment(const char *buffer, unsigned long bufsz,
 				return -EINVAL;
 			}
 
-			if (dest == (void *) load_addr) {
-				struct page *page;
-				char *ptr;
-				size_t uchunk, mchunk;
-
-				page = kmap_to_page(addr);
-
-				ptr = kmap(page);
-				ptr += load_addr & ~PAGE_MASK;
-				mchunk = min_t(size_t, memsz,
-					       PAGE_SIZE - (load_addr & ~PAGE_MASK));
-				uchunk = min(bufsz, mchunk);
-				memcpy(ptr, buffer, uchunk);
-
-				kunmap(page);
+			if (dest == (void *) state.maddr) {
+				int ret;
 
-				bufsz -= uchunk;
-				load_addr += mchunk;
-				buffer += mchunk;
-				memsz -= mchunk;
+				ret = kimage_update_page(kmap_to_page(addr),
+							 &state);
+				if (ret)
+					return ret;
 			}
 			dest += PAGE_SIZE;
 		}
@@ -791,31 +845,30 @@ int kexec_update_segment(const char *buffer, unsigned long bufsz,
 static int kimage_load_normal_segment(struct kimage *image,
 					 struct kexec_segment *segment)
 {
-	unsigned long maddr;
-	size_t ubytes, mbytes;
-	int result;
-	unsigned char __user *buf = NULL;
-	unsigned char *kbuf = NULL;
-
-	result = 0;
-	if (image->file_mode)
-		kbuf = segment->kbuf;
-	else
-		buf = segment->buf;
-	ubytes = segment->bufsz;
-	mbytes = segment->memsz;
-	maddr = segment->mem;
+	int result = 0;
+	struct kimage_update_buffer_state state;
+
+	/* For file based kexec, source pages are in kernel memory */
+	if (image->file_mode) {
+		state.kbuf = segment->kbuf;
+		state.from_kernel = true;
+	} else {
+		state.buf = segment->buf;
+		state.from_kernel = false;
+	}
+	state.ubytes = segment->bufsz;
+	state.mbytes = segment->memsz;
+	state.maddr = segment->mem;
+	state.clear_pages = true;
 
-	result = kimage_set_destination(image, maddr);
+	result = kimage_set_destination(image, state.maddr);
 	if (result < 0)
 		goto out;
 
-	while (mbytes) {
+	while (state.mbytes) {
 		struct page *page;
-		char *ptr;
-		size_t uchunk, mchunk;
 
-		page = kimage_alloc_page(image, GFP_HIGHUSER, maddr);
+		page = kimage_alloc_page(image, GFP_HIGHUSER, state.maddr);
 		if (!page) {
 			result  = -ENOMEM;
 			goto out;
@@ -825,31 +878,9 @@ static int kimage_load_normal_segment(struct kimage *image,
 		if (result < 0)
 			goto out;
 
-		ptr = kmap(page);
-		/* Start with a clear page */
-		clear_page(ptr);
-		ptr += maddr & ~PAGE_MASK;
-		mchunk = min_t(size_t, mbytes,
-				PAGE_SIZE - (maddr & ~PAGE_MASK));
-		uchunk = min(ubytes, mchunk);
-
-		/* For file based kexec, source pages are in kernel memory */
-		if (image->file_mode)
-			memcpy(ptr, kbuf, uchunk);
-		else
-			result = copy_from_user(ptr, buf, uchunk);
-		kunmap(page);
-		if (result) {
-			result = -EFAULT;
+		result = kimage_update_page(page, &state);
+		if (result)
 			goto out;
-		}
-		ubytes -= uchunk;
-		maddr  += mchunk;
-		if (image->file_mode)
-			kbuf += mchunk;
-		else
-			buf += mchunk;
-		mbytes -= mchunk;
 	}
 out:
 	return result;
-- 
1.9.1


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 6/6] IMA: Demonstration code for kexec buffer passing.
  2016-06-21  1:44 ` Thiago Jung Bauermann
@ 2016-06-21  1:44   ` Thiago Jung Bauermann
  -1 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: kexec, x86, linux-kernel, Eric Biederman, Dave Young,
	Michael Ellerman, Mimi Zohar, Eric Richter,
	Thiago Jung Bauermann

This shows how kernel code can use the kexec buffer passing mechanism
to pass information to the next kernel.

This patch is not intended to be committed.

Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
 include/linux/ima.h                   | 11 +++++
 kernel/kexec_file.c                   |  4 ++
 security/integrity/ima/ima.h          |  5 +++
 security/integrity/ima/ima_init.c     | 26 ++++++++++++
 security/integrity/ima/ima_template.c | 79 +++++++++++++++++++++++++++++++++++
 5 files changed, 125 insertions(+)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index 0eb7c2e7f0d6..96528d007139 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -11,6 +11,7 @@
 #define _LINUX_IMA_H
 
 #include <linux/fs.h>
+#include <linux/kexec.h>
 struct linux_binprm;
 
 #ifdef CONFIG_IMA
@@ -23,6 +24,10 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
 			      enum kernel_read_file_id id);
 extern void ima_post_path_mknod(struct dentry *dentry);
 
+#ifdef CONFIG_KEXEC_FILE
+extern void ima_add_kexec_buffer(struct kimage *image);
+#endif
+
 #else
 static inline int ima_bprm_check(struct linux_binprm *bprm)
 {
@@ -60,6 +65,12 @@ static inline void ima_post_path_mknod(struct dentry *dentry)
 	return;
 }
 
+#ifdef CONFIG_KEXEC_FILE
+static inline void ima_add_kexec_buffer(struct kimage *image)
+{
+}
+#endif
+
 #endif /* CONFIG_IMA */
 
 #ifdef CONFIG_IMA_APPRAISE
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 79d09a7784d8..143c70d2ef1c 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -20,6 +20,7 @@
 #include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/fs.h>
+#include <linux/ima.h>
 #include <crypto/hash.h>
 #include <crypto/sha.h>
 #include <linux/syscalls.h>
@@ -261,6 +262,9 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
 		}
 	}
 
+	/* IMA needs to pass the measurement list to the next kernel. */
+	ima_add_kexec_buffer(image);
+
 	/* Call arch image load handlers */
 	ldata = arch_kexec_kernel_image_load(image);
 
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index d3a939bf2781..940f68f3ccc9 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -101,6 +101,11 @@ struct ima_queue_entry {
 };
 extern struct list_head ima_measurements;	/* list of all measurements */
 
+#ifdef CONFIG_KEXEC_FILE
+extern void *kexec_buffer;
+extern size_t kexec_buffer_size;
+#endif
+
 /* Internal IMA function definitions */
 int ima_init(void);
 int ima_fs_init(void);
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 5d679a685616..aaa2fc536ca4 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -21,6 +21,7 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/kexec.h>
 
 #include "ima.h"
 
@@ -103,6 +104,29 @@ void __init ima_load_x509(void)
 }
 #endif
 
+#ifdef CONFIG_KEXEC_FILE
+static void ima_load_kexec_buffer(void)
+{
+	int rc;
+
+	/* Fetch the buffer from the previous kernel, if any. */
+	rc = kexec_get_handover_buffer(&kexec_buffer, &kexec_buffer_size);
+	if (rc == 0) {
+		/* Demonstrate that buffer handover works. */
+		pr_err("kexec buffer contents: %s\n", (char *) kexec_buffer);
+		pr_err("kexec buffer contents after update: %s\n",
+		       (char *) kexec_buffer + 4 * PAGE_SIZE + 10);
+
+		kexec_free_handover_buffer();
+	} else if (rc == -ENOENT)
+		pr_debug("No kexec buffer from the previous kernel.\n");
+	else
+		pr_debug("Error restoring kexec buffer: %d\n", rc);
+}
+#else
+static void ima_load_kexec_buffer(void) { }
+#endif
+
 int __init ima_init(void)
 {
 	u8 pcr_i[TPM_DIGEST_SIZE];
@@ -133,5 +157,7 @@ int __init ima_init(void)
 
 	ima_init_policy();
 
+	ima_load_kexec_buffer();
+
 	return ima_fs_init();
 }
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index febd12ed9b55..c5e81af8cb9c 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -15,6 +15,8 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/kexec.h>
+#include <linux/reboot.h>
 #include "ima.h"
 #include "ima_template_lib.h"
 
@@ -182,6 +184,83 @@ static int template_desc_init_fields(const char *template_fmt,
 	return 0;
 }
 
+#ifdef CONFIG_KEXEC_FILE
+void *kexec_buffer = NULL;
+size_t kexec_buffer_size = 0;
+
+/* Physical address of the measurement buffer in the next kernel. */
+unsigned long kexec_buffer_load_addr = 0;
+
+/*
+ * Called during reboot. IMA can add here new events that were generated after
+ * the kexec image was loaded.
+ */
+static int ima_update_kexec_buffer(struct notifier_block *self,
+				   unsigned long action, void *data)
+{
+	int ret;
+
+	if (!kexec_in_progress)
+		return NOTIFY_OK;
+
+	/*
+	 * Add content deep in the buffer to show that we can update
+	 * all of it.
+	 */
+	strcpy(kexec_buffer + 4 * PAGE_SIZE + 10,
+	       "Updated kexec buffer contents.");
+
+	ret = kexec_update_segment(kexec_buffer, kexec_buffer_size,
+				   kexec_buffer_load_addr, kexec_buffer_size);
+	if (ret)
+		pr_err("Error updating kexec buffer: %d\n", ret);
+
+	return NOTIFY_OK;
+}
+
+struct notifier_block update_buffer_nb = {
+	.notifier_call = ima_update_kexec_buffer,
+};
+
+/*
+ * Called during kexec_file_load so that IMA can add a segment to the kexec
+ * image with the measurement event log for the next kernel.
+ */
+void ima_add_kexec_buffer(struct kimage *image)
+{
+	int ret;
+
+	if (!kexec_can_hand_over_buffer())
+		return;
+
+	/* Create a relatively big buffer, for testing. */
+	kexec_buffer_size = 5 * PAGE_SIZE;
+	kexec_buffer = kzalloc(kexec_buffer_size, GFP_KERNEL);
+	if (!kexec_buffer) {
+		pr_err("Not enough memory for the kexec measurement buffer.\n");
+		return;
+	}
+
+	/* Add some content for demonstration purposes. */
+	strcpy(kexec_buffer, "Buffer contents at kexec load time.");
+
+	/* Ask not to checksum the segment, we may have to update it later. */
+	ret = kexec_add_handover_buffer(image, kexec_buffer, kexec_buffer_size,
+					kexec_buffer_size, PAGE_SIZE, 0,
+					ULONG_MAX, true, false,
+					&kexec_buffer_load_addr);
+	if (ret) {
+		pr_err("Error passing over kexec measurement buffer.\n");
+		return;
+	}
+
+	register_reboot_notifier(&update_buffer_nb);
+
+	pr_debug("kexec measurement buffer for the loaded kernel at 0x%lx.\n",
+		 kexec_buffer_load_addr);
+}
+#endif /* CONFIG_KEXEC_FILE */
+
 struct ima_template_desc *ima_template_desc_current(void)
 {
 	if (!ima_template)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 6/6] IMA: Demonstration code for kexec buffer passing.
@ 2016-06-21  1:44   ` Thiago Jung Bauermann
  0 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-21  1:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Michael Ellerman, x86, kexec, linux-kernel, Eric Biederman,
	Thiago Jung Bauermann, Mimi Zohar, Dave Young, Eric Richter

This shows how kernel code can use the kexec buffer passing mechanism
to pass information to the next kernel.

This patch is not intended to be committed.

Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
 include/linux/ima.h                   | 11 +++++
 kernel/kexec_file.c                   |  4 ++
 security/integrity/ima/ima.h          |  5 +++
 security/integrity/ima/ima_init.c     | 26 ++++++++++++
 security/integrity/ima/ima_template.c | 79 +++++++++++++++++++++++++++++++++++
 5 files changed, 125 insertions(+)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index 0eb7c2e7f0d6..96528d007139 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -11,6 +11,7 @@
 #define _LINUX_IMA_H
 
 #include <linux/fs.h>
+#include <linux/kexec.h>
 struct linux_binprm;
 
 #ifdef CONFIG_IMA
@@ -23,6 +24,10 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
 			      enum kernel_read_file_id id);
 extern void ima_post_path_mknod(struct dentry *dentry);
 
+#ifdef CONFIG_KEXEC_FILE
+extern void ima_add_kexec_buffer(struct kimage *image);
+#endif
+
 #else
 static inline int ima_bprm_check(struct linux_binprm *bprm)
 {
@@ -60,6 +65,12 @@ static inline void ima_post_path_mknod(struct dentry *dentry)
 	return;
 }
 
+#ifdef CONFIG_KEXEC_FILE
+static inline void ima_add_kexec_buffer(struct kimage *image)
+{
+}
+#endif
+
 #endif /* CONFIG_IMA */
 
 #ifdef CONFIG_IMA_APPRAISE
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 79d09a7784d8..143c70d2ef1c 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -20,6 +20,7 @@
 #include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/fs.h>
+#include <linux/ima.h>
 #include <crypto/hash.h>
 #include <crypto/sha.h>
 #include <linux/syscalls.h>
@@ -261,6 +262,9 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
 		}
 	}
 
+	/* IMA needs to pass the measurement list to the next kernel. */
+	ima_add_kexec_buffer(image);
+
 	/* Call arch image load handlers */
 	ldata = arch_kexec_kernel_image_load(image);
 
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index d3a939bf2781..940f68f3ccc9 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -101,6 +101,11 @@ struct ima_queue_entry {
 };
 extern struct list_head ima_measurements;	/* list of all measurements */
 
+#ifdef CONFIG_KEXEC_FILE
+extern void *kexec_buffer;
+extern size_t kexec_buffer_size;
+#endif
+
 /* Internal IMA function definitions */
 int ima_init(void);
 int ima_fs_init(void);
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 5d679a685616..aaa2fc536ca4 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -21,6 +21,7 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/kexec.h>
 
 #include "ima.h"
 
@@ -103,6 +104,29 @@ void __init ima_load_x509(void)
 }
 #endif
 
+#ifdef CONFIG_KEXEC_FILE
+static void ima_load_kexec_buffer(void)
+{
+	int rc;
+
+	/* Fetch the buffer from the previous kernel, if any. */
+	rc = kexec_get_handover_buffer(&kexec_buffer, &kexec_buffer_size);
+	if (rc == 0) {
+		/* Demonstrate that buffer handover works. */
+		pr_err("kexec buffer contents: %s\n", (char *) kexec_buffer);
+		pr_err("kexec buffer contents after update: %s\n",
+		       (char *) kexec_buffer + 4 * PAGE_SIZE + 10);
+
+		kexec_free_handover_buffer();
+	} else if (rc == -ENOENT)
+		pr_debug("No kexec buffer from the previous kernel.\n");
+	else
+		pr_debug("Error restoring kexec buffer: %d\n", rc);
+}
+#else
+static void ima_load_kexec_buffer(void) { }
+#endif
+
 int __init ima_init(void)
 {
 	u8 pcr_i[TPM_DIGEST_SIZE];
@@ -133,5 +157,7 @@ int __init ima_init(void)
 
 	ima_init_policy();
 
+	ima_load_kexec_buffer();
+
 	return ima_fs_init();
 }
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index febd12ed9b55..c5e81af8cb9c 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -15,6 +15,8 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/kexec.h>
+#include <linux/reboot.h>
 #include "ima.h"
 #include "ima_template_lib.h"
 
@@ -182,6 +184,83 @@ static int template_desc_init_fields(const char *template_fmt,
 	return 0;
 }
 
+#ifdef CONFIG_KEXEC_FILE
+void *kexec_buffer = NULL;
+size_t kexec_buffer_size = 0;
+
+/* Physical address of the measurement buffer in the next kernel. */
+unsigned long kexec_buffer_load_addr = 0;
+
+/*
+ * Called during reboot. IMA can add here new events that were generated after
+ * the kexec image was loaded.
+ */
+static int ima_update_kexec_buffer(struct notifier_block *self,
+				   unsigned long action, void *data)
+{
+	int ret;
+
+	if (!kexec_in_progress)
+		return NOTIFY_OK;
+
+	/*
+	 * Add content deep in the buffer to show that we can update
+	 * all of it.
+	 */
+	strcpy(kexec_buffer + 4 * PAGE_SIZE + 10,
+	       "Updated kexec buffer contents.");
+
+	ret = kexec_update_segment(kexec_buffer, kexec_buffer_size,
+				   kexec_buffer_load_addr, kexec_buffer_size);
+	if (ret)
+		pr_err("Error updating kexec buffer: %d\n", ret);
+
+	return NOTIFY_OK;
+}
+
+struct notifier_block update_buffer_nb = {
+	.notifier_call = ima_update_kexec_buffer,
+};
+
+/*
+ * Called during kexec_file_load so that IMA can add a segment to the kexec
+ * image with the measurement event log for the next kernel.
+ */
+void ima_add_kexec_buffer(struct kimage *image)
+{
+	int ret;
+
+	if (!kexec_can_hand_over_buffer())
+		return;
+
+	/* Create a relatively big buffer, for testing. */
+	kexec_buffer_size = 5 * PAGE_SIZE;
+	kexec_buffer = kzalloc(kexec_buffer_size, GFP_KERNEL);
+	if (!kexec_buffer) {
+		pr_err("Not enough memory for the kexec measurement buffer.\n");
+		return;
+	}
+
+	/* Add some content for demonstration purposes. */
+	strcpy(kexec_buffer, "Buffer contents at kexec load time.");
+
+	/* Ask not to checksum the segment, we may have to update it later. */
+	ret = kexec_add_handover_buffer(image, kexec_buffer, kexec_buffer_size,
+					kexec_buffer_size, PAGE_SIZE, 0,
+					ULONG_MAX, true, false,
+					&kexec_buffer_load_addr);
+	if (ret) {
+		pr_err("Error passing over kexec measurement buffer.\n");
+		return;
+	}
+
+	register_reboot_notifier(&update_buffer_nb);
+
+	pr_debug("kexec measurement buffer for the loaded kernel at 0x%lx.\n",
+		 kexec_buffer_load_addr);
+}
+#endif /* CONFIG_KEXEC_FILE */
+
 struct ima_template_desc *ima_template_desc_current(void)
 {
 	if (!ima_template)
-- 
1.9.1


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 0/6] kexec_file: Add buffer hand-over for the next kernel
  2016-06-21  1:44 ` Thiago Jung Bauermann
@ 2016-06-22  1:20   ` Dave Young
  -1 siblings, 0 replies; 20+ messages in thread
From: Dave Young @ 2016-06-22  1:20 UTC (permalink / raw)
  To: Thiago Jung Bauermann
  Cc: linuxppc-dev, kexec, x86, linux-kernel, Eric Biederman,
	Michael Ellerman, Mimi Zohar, Eric Richter

On 06/20/16 at 10:44pm, Thiago Jung Bauermann wrote:
> Hello,
> 
> This patch series implements a mechanism which allows the kernel to pass on
> a buffer to the kernel that will be kexec'd. This buffer is passed as a
> segment which is added to the kimage when it is being prepared by
> kexec_file_load.
> 
> How the second kernel is informed of this buffer is architecture-specific.
> On PowerPC, this is done via the device tree, by checking the properties
> /chosen/linux,kexec-handover-buffer-start and
> /chosen/linux,kexec-handover-buffer-end, which is analogous to how the
> kernel finds the initrd.
> 
> This feature was implemented because the Integrity Measurement Architecture
> subsystem needs to preserve its measurement list accross the kexec reboot.
> This is so that IMA can implement trusted boot support on the OpenPower
> platform, because on such systems an intermediary Linux instance running as
> part of the firmware is used to boot the target operating system via kexec.
> Using this mechanism, IMA on this intermediary instance can hand over to the
> target OS the measurements of the components that were used to boot it.

We have CONFIG_KEXEC_VERIFY_SIG, why not verifying the kernel to be
loaded instead?  I feel IMA should rebuild its measurement instead of
passing it to another kernel. Kexec reboot is also a reboot. If we have
to preserve something get from firmware we can do it, but other than
that I think it sounds not a good idea.

> 
> Because there could be additional measurement events between the
> kexec_file_load call and the actual reboot, IMA needs a way to update the
> buffer with those additional events before rebooting. One can minimize
> the interval between the kexec_file_load and the reboot syscalls, but as
> small as it can be, there is always the possibility that the measurement
> list will be out of date at the time of reboot.
> 
> To address this issue, this patch series also introduces kexec_update_segment,
> which allows a reboot notifier to change the contents of the image segment
> during the reboot process.
> 
> There's one patch which makes kimage_load_normal_segment and
> kexec_update_segment share code. It's not much code that they can share
> though, so I'm not sure if it's worth including this patch.
> 
> The last patch is not intended to be merged, it just demonstrates how this
> feature can be used.
> 
> This series applies on top of v2 of the "kexec_file_load implementation
> for PowerPC" patch series at:

The kexec_file_load patches should be addressed first, no?

> 
> http://lists.infradead.org/pipermail/kexec/2016-June/016078.html
> 
> Thiago Jung Bauermann (6):
>   kexec_file: Add buffer hand-over support for the next kernel
>   powerpc: kexec_file: Add buffer hand-over support for the next kernel
>   kexec_file: Allow skipping checksum calculation for some segments.
>   kexec_file: Add mechanism to update kexec segments.
>   kexec: Share logic to copy segment page contents.
>   IMA: Demonstration code for kexec buffer passing.
> 
>  arch/powerpc/include/asm/kexec.h       |   9 ++
>  arch/powerpc/kernel/kexec_elf_64.c     |  50 +++++++-
>  arch/powerpc/kernel/machine_kexec_64.c |  64 ++++++++++
>  arch/x86/kernel/crash.c                |   4 +-
>  arch/x86/kernel/kexec-bzimage64.c      |   6 +-
>  include/linux/ima.h                    |  11 ++
>  include/linux/kexec.h                  |  47 +++++++-
>  kernel/kexec_core.c                    | 205 ++++++++++++++++++++++++++-------
>  kernel/kexec_file.c                    | 102 ++++++++++++++--
>  security/integrity/ima/ima.h           |   5 +
>  security/integrity/ima/ima_init.c      |  26 +++++
>  security/integrity/ima/ima_template.c  |  79 +++++++++++++
>  12 files changed, 547 insertions(+), 61 deletions(-)
> 
> -- 
> 1.9.1
> 

Thanks
Dave

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 0/6] kexec_file: Add buffer hand-over for the next kernel
@ 2016-06-22  1:20   ` Dave Young
  0 siblings, 0 replies; 20+ messages in thread
From: Dave Young @ 2016-06-22  1:20 UTC (permalink / raw)
  To: Thiago Jung Bauermann
  Cc: Michael Ellerman, x86, kexec, linux-kernel, Eric Biederman,
	Mimi Zohar, linuxppc-dev, Eric Richter

On 06/20/16 at 10:44pm, Thiago Jung Bauermann wrote:
> Hello,
> 
> This patch series implements a mechanism which allows the kernel to pass on
> a buffer to the kernel that will be kexec'd. This buffer is passed as a
> segment which is added to the kimage when it is being prepared by
> kexec_file_load.
> 
> How the second kernel is informed of this buffer is architecture-specific.
> On PowerPC, this is done via the device tree, by checking the properties
> /chosen/linux,kexec-handover-buffer-start and
> /chosen/linux,kexec-handover-buffer-end, which is analogous to how the
> kernel finds the initrd.
> 
> This feature was implemented because the Integrity Measurement Architecture
> subsystem needs to preserve its measurement list accross the kexec reboot.
> This is so that IMA can implement trusted boot support on the OpenPower
> platform, because on such systems an intermediary Linux instance running as
> part of the firmware is used to boot the target operating system via kexec.
> Using this mechanism, IMA on this intermediary instance can hand over to the
> target OS the measurements of the components that were used to boot it.

We have CONFIG_KEXEC_VERIFY_SIG, why not verifying the kernel to be
loaded instead?  I feel IMA should rebuild its measurement instead of
passing it to another kernel. Kexec reboot is also a reboot. If we have
to preserve something get from firmware we can do it, but other than
that I think it sounds not a good idea.

> 
> Because there could be additional measurement events between the
> kexec_file_load call and the actual reboot, IMA needs a way to update the
> buffer with those additional events before rebooting. One can minimize
> the interval between the kexec_file_load and the reboot syscalls, but as
> small as it can be, there is always the possibility that the measurement
> list will be out of date at the time of reboot.
> 
> To address this issue, this patch series also introduces kexec_update_segment,
> which allows a reboot notifier to change the contents of the image segment
> during the reboot process.
> 
> There's one patch which makes kimage_load_normal_segment and
> kexec_update_segment share code. It's not much code that they can share
> though, so I'm not sure if it's worth including this patch.
> 
> The last patch is not intended to be merged, it just demonstrates how this
> feature can be used.
> 
> This series applies on top of v2 of the "kexec_file_load implementation
> for PowerPC" patch series at:

The kexec_file_load patches should be addressed first, no?

> 
> http://lists.infradead.org/pipermail/kexec/2016-June/016078.html
> 
> Thiago Jung Bauermann (6):
>   kexec_file: Add buffer hand-over support for the next kernel
>   powerpc: kexec_file: Add buffer hand-over support for the next kernel
>   kexec_file: Allow skipping checksum calculation for some segments.
>   kexec_file: Add mechanism to update kexec segments.
>   kexec: Share logic to copy segment page contents.
>   IMA: Demonstration code for kexec buffer passing.
> 
>  arch/powerpc/include/asm/kexec.h       |   9 ++
>  arch/powerpc/kernel/kexec_elf_64.c     |  50 +++++++-
>  arch/powerpc/kernel/machine_kexec_64.c |  64 ++++++++++
>  arch/x86/kernel/crash.c                |   4 +-
>  arch/x86/kernel/kexec-bzimage64.c      |   6 +-
>  include/linux/ima.h                    |  11 ++
>  include/linux/kexec.h                  |  47 +++++++-
>  kernel/kexec_core.c                    | 205 ++++++++++++++++++++++++++-------
>  kernel/kexec_file.c                    | 102 ++++++++++++++--
>  security/integrity/ima/ima.h           |   5 +
>  security/integrity/ima/ima_init.c      |  26 +++++
>  security/integrity/ima/ima_template.c  |  79 +++++++++++++
>  12 files changed, 547 insertions(+), 61 deletions(-)
> 
> -- 
> 1.9.1
> 

Thanks
Dave

_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 0/6] kexec_file: Add buffer hand-over for the next kernel
  2016-06-22  1:20   ` Dave Young
@ 2016-06-22 13:19     ` Mimi Zohar
  -1 siblings, 0 replies; 20+ messages in thread
From: Mimi Zohar @ 2016-06-22 13:19 UTC (permalink / raw)
  To: Dave Young
  Cc: Thiago Jung Bauermann, linuxppc-dev, kexec, x86, linux-kernel,
	Eric Biederman, Michael Ellerman, Eric Richter

Hi Dave,

On Wed, 2016-06-22 at 09:20 +0800, Dave Young wrote:
> On 06/20/16 at 10:44pm, Thiago Jung Bauermann wrote:
> > Hello,
> > 
> > This patch series implements a mechanism which allows the kernel to pass on
> > a buffer to the kernel that will be kexec'd. This buffer is passed as a
> > segment which is added to the kimage when it is being prepared by
> > kexec_file_load.
> > 
> > How the second kernel is informed of this buffer is architecture-specific.
> > On PowerPC, this is done via the device tree, by checking the properties
> > /chosen/linux,kexec-handover-buffer-start and
> > /chosen/linux,kexec-handover-buffer-end, which is analogous to how the
> > kernel finds the initrd.
> > 
> > This feature was implemented because the Integrity Measurement Architecture
> > subsystem needs to preserve its measurement list accross the kexec reboot.
> > This is so that IMA can implement trusted boot support on the OpenPower
> > platform, because on such systems an intermediary Linux instance running as
> > part of the firmware is used to boot the target operating system via kexec.
> > Using this mechanism, IMA on this intermediary instance can hand over to the
> > target OS the measurements of the components that were used to boot it.
> 
> We have CONFIG_KEXEC_VERIFY_SIG, why not verifying the kernel to be
> loaded instead?  I feel IMA should rebuild its measurement instead of
> passing it to another kernel. Kexec reboot is also a reboot. If we have
> to preserve something get from firmware we can do it, but other than
> that I think it sounds not a good idea.

The signature verification is needed for secure boot.  Carrying the IMA
measurement list across kexec is needed for trusted boot.  In this case,
the boot loader is Linux, which needs to carry the measurements, stored
in memory, across kexec to the target system.

The kernel_read_file_from_fd() calls the pre and post security
kernel_read hooks.  These hooks can verify file signatures, store
measurements in the IMA measurement list and extend the TPM.  To enable
both measuring and appraising (signature verification) of the kernel
image and the initramfs, include the following rules in the IMA policy:

measure func=KEXEC_KERNEL_CHECK
appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig
#
measure func=KEXEC_INITRAMFS_CHECK
appraise func=KEXEC_INITRAMFS_CHECK appraise_type=imasig

Thiago's path set provides the means for carrying the trusted boot
measurements across kexec.

Mimi

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 0/6] kexec_file: Add buffer hand-over for the next kernel
@ 2016-06-22 13:19     ` Mimi Zohar
  0 siblings, 0 replies; 20+ messages in thread
From: Mimi Zohar @ 2016-06-22 13:19 UTC (permalink / raw)
  To: Dave Young
  Cc: Michael Ellerman, x86, kexec, linux-kernel, Eric Biederman,
	Thiago Jung Bauermann, linuxppc-dev, Eric Richter

Hi Dave,

On Wed, 2016-06-22 at 09:20 +0800, Dave Young wrote:
> On 06/20/16 at 10:44pm, Thiago Jung Bauermann wrote:
> > Hello,
> > 
> > This patch series implements a mechanism which allows the kernel to pass on
> > a buffer to the kernel that will be kexec'd. This buffer is passed as a
> > segment which is added to the kimage when it is being prepared by
> > kexec_file_load.
> > 
> > How the second kernel is informed of this buffer is architecture-specific.
> > On PowerPC, this is done via the device tree, by checking the properties
> > /chosen/linux,kexec-handover-buffer-start and
> > /chosen/linux,kexec-handover-buffer-end, which is analogous to how the
> > kernel finds the initrd.
> > 
> > This feature was implemented because the Integrity Measurement Architecture
> > subsystem needs to preserve its measurement list accross the kexec reboot.
> > This is so that IMA can implement trusted boot support on the OpenPower
> > platform, because on such systems an intermediary Linux instance running as
> > part of the firmware is used to boot the target operating system via kexec.
> > Using this mechanism, IMA on this intermediary instance can hand over to the
> > target OS the measurements of the components that were used to boot it.
> 
> We have CONFIG_KEXEC_VERIFY_SIG, why not verifying the kernel to be
> loaded instead?  I feel IMA should rebuild its measurement instead of
> passing it to another kernel. Kexec reboot is also a reboot. If we have
> to preserve something get from firmware we can do it, but other than
> that I think it sounds not a good idea.

The signature verification is needed for secure boot.  Carrying the IMA
measurement list across kexec is needed for trusted boot.  In this case,
the boot loader is Linux, which needs to carry the measurements, stored
in memory, across kexec to the target system.

The kernel_read_file_from_fd() calls the pre and post security
kernel_read hooks.  These hooks can verify file signatures, store
measurements in the IMA measurement list and extend the TPM.  To enable
both measuring and appraising (signature verification) of the kernel
image and the initramfs, include the following rules in the IMA policy:

measure func=KEXEC_KERNEL_CHECK
appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig
#
measure func=KEXEC_INITRAMFS_CHECK
appraise func=KEXEC_INITRAMFS_CHECK appraise_type=imasig

Thiago's path set provides the means for carrying the trusted boot
measurements across kexec.

Mimi


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 0/6] kexec_file: Add buffer hand-over for the next kernel
  2016-06-22  1:20   ` Dave Young
@ 2016-06-22 16:34     ` Thiago Jung Bauermann
  -1 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-22 16:34 UTC (permalink / raw)
  To: Dave Young
  Cc: linuxppc-dev, kexec, x86, linux-kernel, Eric Biederman,
	Michael Ellerman, Mimi Zohar, Eric Richter

Hello Dave,

Thanks for your considerations on this feature.

Am Mittwoch, 22 Juni 2016, 09:20:46 schrieb Dave Young:
> On 06/20/16 at 10:44pm, Thiago Jung Bauermann wrote:
> > This feature was implemented because the Integrity Measurement
> > Architecture subsystem needs to preserve its measurement list accross
> > the kexec reboot. This is so that IMA can implement trusted boot
> > support on the OpenPower platform, because on such systems an
> > intermediary Linux instance running as part of the firmware is used to
> > boot the target operating system via kexec. Using this mechanism, IMA
> > on this intermediary instance can hand over to the target OS the
> > measurements of the components that were used to boot it.
> We have CONFIG_KEXEC_VERIFY_SIG, why not verifying the kernel to be
> loaded instead?  I feel IMA should rebuild its measurement instead of
> passing it to another kernel.

In trusted boot, each stage of the boot process (firmware, boot loader, 
target OS) measures the following stage before passing control to it, and 
records that measurement cumulatively so that the target OS can look back 
and see measurements of all the components that were used from the earliest 
boot stages until the target OS was loaded (including a measurement of the 
OS itself).

If IMA had to rebuild the measurements, it would mean that one stage is 
measuring itself. This violates this design property of the trusted boot 
process (i.e., each boot stage is measured by the one before it) so it's not 
really an option. It has to receive the measurements from the boot stage 
that ran before it.

> Kexec reboot is also a reboot. If we have
> to preserve something get from firmware we can do it, but other than
> that I think it sounds not a good idea.

OpenPower uses a Linux kernel (and initrd with a tiny system image) as a 
boot loader, so in this platform a kexec reboot is not a reboot. It is part 
of the boot process itself as the way of passing control from the boot 
loader to the target OS.

> > This series applies on top of v2 of the "kexec_file_load implementation
> 
> > for PowerPC" patch series at:
> The kexec_file_load patches should be addressed first, no?

Yes. I posted this series for two reasons:

1. The PowerPC maintainer asked why he would want to have the 
kexec_file_load system call, and this feature is one of the reasons. I 
wanted to show that it is not an hypothetical feature, there is a 
functioning implementation.

2. I want to start discussion on this feature with the community early, so 
that I can incorporate feedback and have it ready to be accepted (or closer 
to ready at least) by the time the kexec_file_load patches are accepted.

[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 0/6] kexec_file: Add buffer hand-over for the next kernel
@ 2016-06-22 16:34     ` Thiago Jung Bauermann
  0 siblings, 0 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2016-06-22 16:34 UTC (permalink / raw)
  To: Dave Young
  Cc: Michael Ellerman, x86, kexec, linux-kernel, Eric Biederman,
	Mimi Zohar, linuxppc-dev, Eric Richter

Hello Dave,

Thanks for your considerations on this feature.

Am Mittwoch, 22 Juni 2016, 09:20:46 schrieb Dave Young:
> On 06/20/16 at 10:44pm, Thiago Jung Bauermann wrote:
> > This feature was implemented because the Integrity Measurement
> > Architecture subsystem needs to preserve its measurement list accross
> > the kexec reboot. This is so that IMA can implement trusted boot
> > support on the OpenPower platform, because on such systems an
> > intermediary Linux instance running as part of the firmware is used to
> > boot the target operating system via kexec. Using this mechanism, IMA
> > on this intermediary instance can hand over to the target OS the
> > measurements of the components that were used to boot it.
> We have CONFIG_KEXEC_VERIFY_SIG, why not verifying the kernel to be
> loaded instead?  I feel IMA should rebuild its measurement instead of
> passing it to another kernel.

In trusted boot, each stage of the boot process (firmware, boot loader, 
target OS) measures the following stage before passing control to it, and 
records that measurement cumulatively so that the target OS can look back 
and see measurements of all the components that were used from the earliest 
boot stages until the target OS was loaded (including a measurement of the 
OS itself).

If IMA had to rebuild the measurements, it would mean that one stage is 
measuring itself. This violates this design property of the trusted boot 
process (i.e., each boot stage is measured by the one before it) so it's not 
really an option. It has to receive the measurements from the boot stage 
that ran before it.

> Kexec reboot is also a reboot. If we have
> to preserve something get from firmware we can do it, but other than
> that I think it sounds not a good idea.

OpenPower uses a Linux kernel (and initrd with a tiny system image) as a 
boot loader, so in this platform a kexec reboot is not a reboot. It is part 
of the boot process itself as the way of passing control from the boot 
loader to the target OS.

> > This series applies on top of v2 of the "kexec_file_load implementation
> 
> > for PowerPC" patch series at:
> The kexec_file_load patches should be addressed first, no?

Yes. I posted this series for two reasons:

1. The PowerPC maintainer asked why he would want to have the 
kexec_file_load system call, and this feature is one of the reasons. I 
wanted to show that it is not an hypothetical feature, there is a 
functioning implementation.

2. I want to start discussion on this feature with the community early, so 
that I can incorporate feedback and have it ready to be accepted (or closer 
to ready at least) by the time the kexec_file_load patches are accepted.

[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2016-06-22 16:35 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-21  1:44 [PATCH 0/6] kexec_file: Add buffer hand-over for the next kernel Thiago Jung Bauermann
2016-06-21  1:44 ` Thiago Jung Bauermann
2016-06-21  1:44 ` [PATCH 1/6] kexec_file: Add buffer hand-over support " Thiago Jung Bauermann
2016-06-21  1:44   ` Thiago Jung Bauermann
2016-06-21  1:44 ` [PATCH 2/6] powerpc: " Thiago Jung Bauermann
2016-06-21  1:44   ` Thiago Jung Bauermann
2016-06-21  1:44 ` [PATCH 3/6] kexec_file: Allow skipping checksum calculation for some segments Thiago Jung Bauermann
2016-06-21  1:44   ` Thiago Jung Bauermann
2016-06-21  1:44 ` [PATCH 4/6] kexec_file: Add mechanism to update kexec segments Thiago Jung Bauermann
2016-06-21  1:44   ` Thiago Jung Bauermann
2016-06-21  1:44 ` [PATCH 5/6] kexec: Share logic to copy segment page contents Thiago Jung Bauermann
2016-06-21  1:44   ` Thiago Jung Bauermann
2016-06-21  1:44 ` [PATCH 6/6] IMA: Demonstration code for kexec buffer passing Thiago Jung Bauermann
2016-06-21  1:44   ` Thiago Jung Bauermann
2016-06-22  1:20 ` [PATCH 0/6] kexec_file: Add buffer hand-over for the next kernel Dave Young
2016-06-22  1:20   ` Dave Young
2016-06-22 13:19   ` Mimi Zohar
2016-06-22 13:19     ` Mimi Zohar
2016-06-22 16:34   ` Thiago Jung Bauermann
2016-06-22 16:34     ` Thiago Jung Bauermann

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.