aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/Kconfig3
-rw-r--r--arch/powerpc/Kconfig1
-rw-r--r--arch/powerpc/include/asm/ima.h13
-rw-r--r--arch/powerpc/include/asm/kexec.h1
-rw-r--r--arch/powerpc/kernel/Makefile4
-rw-r--r--arch/powerpc/kernel/ima_kexec.c132
-rw-r--r--arch/powerpc/kernel/machine_kexec_file_64.c5
7 files changed, 158 insertions, 1 deletions
diff --git a/arch/Kconfig b/arch/Kconfig
index 19483aea4bbc..99839c23d453 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -5,6 +5,9 @@
5config KEXEC_CORE 5config KEXEC_CORE
6 bool 6 bool
7 7
8config HAVE_IMA_KEXEC
9 bool
10
8config OPROFILE 11config OPROFILE
9 tristate "OProfile system profiling" 12 tristate "OProfile system profiling"
10 depends on PROFILING 13 depends on PROFILING
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 3da87e198878..a8ee573fe610 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -469,6 +469,7 @@ config KEXEC
469config KEXEC_FILE 469config KEXEC_FILE
470 bool "kexec file based system call" 470 bool "kexec file based system call"
471 select KEXEC_CORE 471 select KEXEC_CORE
472 select HAVE_IMA_KEXEC
472 select BUILD_BIN2C 473 select BUILD_BIN2C
473 depends on PPC64 474 depends on PPC64
474 depends on CRYPTO=y 475 depends on CRYPTO=y
diff --git a/arch/powerpc/include/asm/ima.h b/arch/powerpc/include/asm/ima.h
new file mode 100644
index 000000000000..d5a72dd9b499
--- /dev/null
+++ b/arch/powerpc/include/asm/ima.h
@@ -0,0 +1,13 @@
1#ifndef _ASM_POWERPC_IMA_H
2#define _ASM_POWERPC_IMA_H
3
4int ima_get_kexec_buffer(void **addr, size_t *size);
5int ima_free_kexec_buffer(void);
6
7#ifdef CONFIG_IMA
8void remove_ima_buffer(void *fdt, int chosen_node);
9#else
10static inline void remove_ima_buffer(void *fdt, int chosen_node) {}
11#endif
12
13#endif /* _ASM_POWERPC_IMA_H */
diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
index 6c3b71502fbc..b0fdffb7179b 100644
--- a/arch/powerpc/include/asm/kexec.h
+++ b/arch/powerpc/include/asm/kexec.h
@@ -99,6 +99,7 @@ int setup_purgatory(struct kimage *image, const void *slave_code,
99 unsigned long fdt_load_addr); 99 unsigned long fdt_load_addr);
100int setup_new_fdt(void *fdt, unsigned long initrd_load_addr, 100int setup_new_fdt(void *fdt, unsigned long initrd_load_addr,
101 unsigned long initrd_len, const char *cmdline); 101 unsigned long initrd_len, const char *cmdline);
102int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size);
102#endif /* CONFIG_KEXEC_FILE */ 103#endif /* CONFIG_KEXEC_FILE */
103 104
104#else /* !CONFIG_KEXEC_CORE */ 105#else /* !CONFIG_KEXEC_CORE */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index a3a6047fd395..23f8082d7bfa 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -112,6 +112,10 @@ obj-$(CONFIG_PCI_MSI) += msi.o
112obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o crash.o \ 112obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o crash.o \
113 machine_kexec_$(BITS).o 113 machine_kexec_$(BITS).o
114obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file_$(BITS).o kexec_elf_$(BITS).o 114obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file_$(BITS).o kexec_elf_$(BITS).o
115ifeq ($(CONFIG_HAVE_IMA_KEXEC)$(CONFIG_IMA),yy)
116obj-y += ima_kexec.o
117endif
118
115obj-$(CONFIG_AUDIT) += audit.o 119obj-$(CONFIG_AUDIT) += audit.o
116obj64-$(CONFIG_AUDIT) += compat_audit.o 120obj64-$(CONFIG_AUDIT) += compat_audit.o
117 121
diff --git a/arch/powerpc/kernel/ima_kexec.c b/arch/powerpc/kernel/ima_kexec.c
new file mode 100644
index 000000000000..36e5a5df3804
--- /dev/null
+++ b/arch/powerpc/kernel/ima_kexec.c
@@ -0,0 +1,132 @@
1/*
2 * Copyright (C) 2016 IBM Corporation
3 *
4 * Authors:
5 * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <linux/slab.h>
14#include <linux/kexec.h>
15#include <linux/of.h>
16#include <linux/memblock.h>
17#include <linux/libfdt.h>
18
19static int get_addr_size_cells(int *addr_cells, int *size_cells)
20{
21 struct device_node *root;
22
23 root = of_find_node_by_path("/");
24 if (!root)
25 return -EINVAL;
26
27 *addr_cells = of_n_addr_cells(root);
28 *size_cells = of_n_size_cells(root);
29
30 of_node_put(root);
31
32 return 0;
33}
34
35static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr,
36 size_t *size)
37{
38 int ret, addr_cells, size_cells;
39
40 ret = get_addr_size_cells(&addr_cells, &size_cells);
41 if (ret)
42 return ret;
43
44 if (len < 4 * (addr_cells + size_cells))
45 return -ENOENT;
46
47 *addr = of_read_number(prop, addr_cells);
48 *size = of_read_number(prop + 4 * addr_cells, size_cells);
49
50 return 0;
51}
52
53/**
54 * ima_get_kexec_buffer - get IMA buffer from the previous kernel
55 * @addr: On successful return, set to point to the buffer contents.
56 * @size: On successful return, set to the buffer size.
57 *
58 * Return: 0 on success, negative errno on error.
59 */
60int ima_get_kexec_buffer(void **addr, size_t *size)
61{
62 int ret, len;
63 unsigned long tmp_addr;
64 size_t tmp_size;
65 const void *prop;
66
67 prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len);
68 if (!prop)
69 return -ENOENT;
70
71 ret = do_get_kexec_buffer(prop, len, &tmp_addr, &tmp_size);
72 if (ret)
73 return ret;
74
75 *addr = __va(tmp_addr);
76 *size = tmp_size;
77
78 return 0;
79}
80
81/**
82 * ima_free_kexec_buffer - free memory used by the IMA buffer
83 */
84int ima_free_kexec_buffer(void)
85{
86 int ret;
87 unsigned long addr;
88 size_t size;
89 struct property *prop;
90
91 prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL);
92 if (!prop)
93 return -ENOENT;
94
95 ret = do_get_kexec_buffer(prop->value, prop->length, &addr, &size);
96 if (ret)
97 return ret;
98
99 ret = of_remove_property(of_chosen, prop);
100 if (ret)
101 return ret;
102
103 return memblock_free(addr, size);
104
105}
106
107/**
108 * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
109 *
110 * The IMA measurement buffer is of no use to a subsequent kernel, so we always
111 * remove it from the device tree.
112 */
113void remove_ima_buffer(void *fdt, int chosen_node)
114{
115 int ret, len;
116 unsigned long addr;
117 size_t size;
118 const void *prop;
119
120 prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len);
121 if (!prop)
122 return;
123
124 ret = do_get_kexec_buffer(prop, len, &addr, &size);
125 fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer");
126 if (ret)
127 return;
128
129 ret = delete_fdt_mem_rsv(fdt, addr, size);
130 if (!ret)
131 pr_debug("Removed old IMA buffer reservation.\n");
132}
diff --git a/arch/powerpc/kernel/machine_kexec_file_64.c b/arch/powerpc/kernel/machine_kexec_file_64.c
index 7abc8a75ee48..29331fffad13 100644
--- a/arch/powerpc/kernel/machine_kexec_file_64.c
+++ b/arch/powerpc/kernel/machine_kexec_file_64.c
@@ -27,6 +27,7 @@
27#include <linux/memblock.h> 27#include <linux/memblock.h>
28#include <linux/of_fdt.h> 28#include <linux/of_fdt.h>
29#include <linux/libfdt.h> 29#include <linux/libfdt.h>
30#include <asm/ima.h>
30 31
31#define SLAVE_CODE_SIZE 256 32#define SLAVE_CODE_SIZE 256
32 33
@@ -180,7 +181,7 @@ int setup_purgatory(struct kimage *image, const void *slave_code,
180 * 181 *
181 * Return: 0 on success, or negative errno on error. 182 * Return: 0 on success, or negative errno on error.
182 */ 183 */
183static int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size) 184int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size)
184{ 185{
185 int i, ret, num_rsvs = fdt_num_mem_rsv(fdt); 186 int i, ret, num_rsvs = fdt_num_mem_rsv(fdt);
186 187
@@ -328,6 +329,8 @@ int setup_new_fdt(void *fdt, unsigned long initrd_load_addr,
328 } 329 }
329 } 330 }
330 331
332 remove_ima_buffer(fdt, chosen_node);
333
331 ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0); 334 ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0);
332 if (ret) { 335 if (ret) {
333 pr_err("Error setting up the new device tree.\n"); 336 pr_err("Error setting up the new device tree.\n");