Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc: Move arch independent ima kexec functions to drivers/of/kexec.c

The functions defined in "arch/powerpc/kexec/ima.c" handle setting up
and freeing the resources required to carry over the IMA measurement
list from the current kernel to the next kernel across kexec system call.
These functions do not have architecture specific code, but are
currently limited to powerpc.

Move remove_ima_buffer() and setup_ima_buffer() calls into
of_kexec_alloc_and_setup_fdt() defined in "drivers/of/kexec.c".

Move the remaining architecture independent functions from
"arch/powerpc/kexec/ima.c" to "drivers/of/kexec.c".
Delete "arch/powerpc/kexec/ima.c" and "arch/powerpc/include/asm/ima.h".
Remove references to the deleted files and functions in powerpc and
in ima.

Co-developed-by: Prakhar Srivastava <prsriva@linux.microsoft.com>
Signed-off-by: Prakhar Srivastava <prsriva@linux.microsoft.com>
Signed-off-by: Lakshmi Ramasubramanian <nramas@linux.microsoft.com>
Reviewed-by: Thiago Jung Bauermann <bauerman@linux.ibm.com>
Tested-by: Thiago Jung Bauermann <bauerman@linux.ibm.com>
Signed-off-by: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20210221174930.27324-11-nramas@linux.microsoft.com

authored by

Lakshmi Ramasubramanian and committed by
Rob Herring
fee3ff99 39652741

+243 -272
-27
arch/powerpc/include/asm/ima.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #ifndef _ASM_POWERPC_IMA_H 3 - #define _ASM_POWERPC_IMA_H 4 - 5 - struct kimage; 6 - 7 - int ima_get_kexec_buffer(void **addr, size_t *size); 8 - int ima_free_kexec_buffer(void); 9 - 10 - #ifdef CONFIG_IMA 11 - void remove_ima_buffer(void *fdt, int chosen_node); 12 - #else 13 - static inline void remove_ima_buffer(void *fdt, int chosen_node) {} 14 - #endif 15 - 16 - #ifdef CONFIG_IMA_KEXEC 17 - int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node); 18 - #else 19 - static inline int setup_ima_buffer(const struct kimage *image, void *fdt, 20 - int chosen_node) 21 - { 22 - remove_ima_buffer(fdt, chosen_node); 23 - return 0; 24 - } 25 - #endif /* CONFIG_IMA_KEXEC */ 26 - 27 - #endif /* _ASM_POWERPC_IMA_H */
-3
arch/powerpc/include/asm/kexec.h
··· 115 115 int setup_purgatory(struct kimage *image, const void *slave_code, 116 116 const void *fdt, unsigned long kernel_load_addr, 117 117 unsigned long fdt_load_addr); 118 - int setup_new_fdt(const struct kimage *image, void *fdt, 119 - unsigned long initrd_load_addr, unsigned long initrd_len, 120 - const char *cmdline); 121 118 int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size); 122 119 123 120 #ifdef CONFIG_PPC64
-7
arch/powerpc/kexec/Makefile
··· 9 9 10 10 obj-$(CONFIG_KEXEC_FILE) += file_load.o ranges.o file_load_$(BITS).o elf_$(BITS).o 11 11 12 - ifdef CONFIG_HAVE_IMA_KEXEC 13 - ifdef CONFIG_IMA 14 - obj-y += ima.o 15 - endif 16 - endif 17 - 18 - 19 12 # Disable GCOV, KCOV & sanitizers in odd or sensitive code 20 13 GCOV_PROFILE_core_$(BITS).o := n 21 14 KCOV_INSTRUMENT_core_$(BITS).o := n
-25
arch/powerpc/kexec/file_load.c
··· 19 19 #include <linux/of_fdt.h> 20 20 #include <linux/libfdt.h> 21 21 #include <asm/setup.h> 22 - #include <asm/ima.h> 23 22 24 23 #define SLAVE_CODE_SIZE 256 /* First 0x100 bytes */ 25 24 ··· 138 139 } 139 140 140 141 return -ENOENT; 141 - } 142 - 143 - /* 144 - * setup_new_fdt - modify /chosen and memory reservation for the next kernel 145 - * @image: kexec image being loaded. 146 - * @fdt: Flattened device tree for the next kernel. 147 - * @initrd_load_addr: Address where the next initrd will be loaded. 148 - * @initrd_len: Size of the next initrd, or 0 if there will be none. 149 - * @cmdline: Command line for the next kernel, or NULL if there will 150 - * be none. 151 - * 152 - * Return: 0 on success, or negative errno on error. 153 - */ 154 - int setup_new_fdt(const struct kimage *image, void *fdt, 155 - unsigned long initrd_load_addr, unsigned long initrd_len, 156 - const char *cmdline) 157 - { 158 - int ret; 159 - 160 - ret = setup_ima_buffer(image, fdt, fdt_path_offset(fdt, "/chosen")); 161 - if (ret) 162 - pr_err("Error setting up the new device tree.\n"); 163 - 164 - return ret; 165 142 }
-4
arch/powerpc/kexec/file_load_64.c
··· 979 979 struct crash_mem *umem = NULL, *rmem = NULL; 980 980 int i, nr_ranges, ret; 981 981 982 - ret = setup_new_fdt(image, fdt, initrd_load_addr, initrd_len, cmdline); 983 - if (ret) 984 - goto out; 985 - 986 982 /* 987 983 * Restrict memory usage for kdump kernel by setting up 988 984 * usable memory ranges and memory reserve map.
-202
arch/powerpc/kexec/ima.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-or-later 2 - /* 3 - * Copyright (C) 2016 IBM Corporation 4 - * 5 - * Authors: 6 - * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com> 7 - */ 8 - 9 - #include <linux/slab.h> 10 - #include <linux/kexec.h> 11 - #include <linux/of.h> 12 - #include <linux/memblock.h> 13 - #include <linux/libfdt.h> 14 - 15 - static int get_addr_size_cells(int *addr_cells, int *size_cells) 16 - { 17 - struct device_node *root; 18 - 19 - root = of_find_node_by_path("/"); 20 - if (!root) 21 - return -EINVAL; 22 - 23 - *addr_cells = of_n_addr_cells(root); 24 - *size_cells = of_n_size_cells(root); 25 - 26 - of_node_put(root); 27 - 28 - return 0; 29 - } 30 - 31 - static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr, 32 - size_t *size) 33 - { 34 - int ret, addr_cells, size_cells; 35 - 36 - ret = get_addr_size_cells(&addr_cells, &size_cells); 37 - if (ret) 38 - return ret; 39 - 40 - if (len < 4 * (addr_cells + size_cells)) 41 - return -ENOENT; 42 - 43 - *addr = of_read_number(prop, addr_cells); 44 - *size = of_read_number(prop + 4 * addr_cells, size_cells); 45 - 46 - return 0; 47 - } 48 - 49 - /** 50 - * ima_get_kexec_buffer - get IMA buffer from the previous kernel 51 - * @addr: On successful return, set to point to the buffer contents. 52 - * @size: On successful return, set to the buffer size. 53 - * 54 - * Return: 0 on success, negative errno on error. 55 - */ 56 - int ima_get_kexec_buffer(void **addr, size_t *size) 57 - { 58 - int ret, len; 59 - unsigned long tmp_addr; 60 - size_t tmp_size; 61 - const void *prop; 62 - 63 - prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len); 64 - if (!prop) 65 - return -ENOENT; 66 - 67 - ret = do_get_kexec_buffer(prop, len, &tmp_addr, &tmp_size); 68 - if (ret) 69 - return ret; 70 - 71 - *addr = __va(tmp_addr); 72 - *size = tmp_size; 73 - 74 - return 0; 75 - } 76 - 77 - /** 78 - * ima_free_kexec_buffer - free memory used by the IMA buffer 79 - */ 80 - int ima_free_kexec_buffer(void) 81 - { 82 - int ret; 83 - unsigned long addr; 84 - size_t size; 85 - struct property *prop; 86 - 87 - prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL); 88 - if (!prop) 89 - return -ENOENT; 90 - 91 - ret = do_get_kexec_buffer(prop->value, prop->length, &addr, &size); 92 - if (ret) 93 - return ret; 94 - 95 - ret = of_remove_property(of_chosen, prop); 96 - if (ret) 97 - return ret; 98 - 99 - return memblock_free(addr, size); 100 - 101 - } 102 - 103 - /** 104 - * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt 105 - * 106 - * The IMA measurement buffer is of no use to a subsequent kernel, so we always 107 - * remove it from the device tree. 108 - */ 109 - void remove_ima_buffer(void *fdt, int chosen_node) 110 - { 111 - int ret, len; 112 - unsigned long addr; 113 - size_t size; 114 - const void *prop; 115 - 116 - prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len); 117 - if (!prop) 118 - return; 119 - 120 - ret = do_get_kexec_buffer(prop, len, &addr, &size); 121 - fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer"); 122 - if (ret) 123 - return; 124 - 125 - ret = delete_fdt_mem_rsv(fdt, addr, size); 126 - if (!ret) 127 - pr_debug("Removed old IMA buffer reservation.\n"); 128 - } 129 - 130 - #ifdef CONFIG_IMA_KEXEC 131 - static int write_number(void *p, u64 value, int cells) 132 - { 133 - if (cells == 1) { 134 - u32 tmp; 135 - 136 - if (value > U32_MAX) 137 - return -EINVAL; 138 - 139 - tmp = cpu_to_be32(value); 140 - memcpy(p, &tmp, sizeof(tmp)); 141 - } else if (cells == 2) { 142 - u64 tmp; 143 - 144 - tmp = cpu_to_be64(value); 145 - memcpy(p, &tmp, sizeof(tmp)); 146 - } else 147 - return -EINVAL; 148 - 149 - return 0; 150 - } 151 - 152 - /** 153 - * setup_ima_buffer - add IMA buffer information to the fdt 154 - * @image: kexec image being loaded. 155 - * @fdt: Flattened device tree for the next kernel. 156 - * @chosen_node: Offset to the chosen node. 157 - * 158 - * Return: 0 on success, or negative errno on error. 159 - */ 160 - int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node) 161 - { 162 - int ret, addr_cells, size_cells, entry_size; 163 - u8 value[16]; 164 - 165 - remove_ima_buffer(fdt, chosen_node); 166 - if (!image->ima_buffer_size) 167 - return 0; 168 - 169 - ret = get_addr_size_cells(&addr_cells, &size_cells); 170 - if (ret) 171 - return ret; 172 - 173 - entry_size = 4 * (addr_cells + size_cells); 174 - 175 - if (entry_size > sizeof(value)) 176 - return -EINVAL; 177 - 178 - ret = write_number(value, image->ima_buffer_addr, addr_cells); 179 - if (ret) 180 - return ret; 181 - 182 - ret = write_number(value + 4 * addr_cells, image->ima_buffer_size, 183 - size_cells); 184 - if (ret) 185 - return ret; 186 - 187 - ret = fdt_setprop(fdt, chosen_node, "linux,ima-kexec-buffer", value, 188 - entry_size); 189 - if (ret < 0) 190 - return -EINVAL; 191 - 192 - ret = fdt_add_mem_rsv(fdt, image->ima_buffer_addr, 193 - image->ima_buffer_size); 194 - if (ret) 195 - return -EINVAL; 196 - 197 - pr_debug("IMA buffer at 0x%llx, size = 0x%zx\n", 198 - image->ima_buffer_addr, image->ima_buffer_size); 199 - 200 - return 0; 201 - } 202 - #endif /* CONFIG_IMA_KEXEC */
+240
drivers/of/kexec.c
··· 11 11 12 12 #include <linux/kernel.h> 13 13 #include <linux/kexec.h> 14 + #include <linux/memblock.h> 14 15 #include <linux/libfdt.h> 15 16 #include <linux/of.h> 16 17 #include <linux/of_fdt.h> ··· 69 68 70 69 return -ENOENT; 71 70 } 71 + 72 + /** 73 + * get_addr_size_cells - Get address and size of root node 74 + * 75 + * @addr_cells: Return address of the root node 76 + * @size_cells: Return size of the root node 77 + * 78 + * Return: 0 on success, or negative errno on error. 79 + */ 80 + static int get_addr_size_cells(int *addr_cells, int *size_cells) 81 + { 82 + struct device_node *root; 83 + 84 + root = of_find_node_by_path("/"); 85 + if (!root) 86 + return -EINVAL; 87 + 88 + *addr_cells = of_n_addr_cells(root); 89 + *size_cells = of_n_size_cells(root); 90 + 91 + of_node_put(root); 92 + 93 + return 0; 94 + } 95 + 96 + /** 97 + * do_get_kexec_buffer - Get address and size of device tree property 98 + * 99 + * @prop: Device tree property 100 + * @len: Size of @prop 101 + * @addr: Return address of the node 102 + * @size: Return size of the node 103 + * 104 + * Return: 0 on success, or negative errno on error. 105 + */ 106 + static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr, 107 + size_t *size) 108 + { 109 + int ret, addr_cells, size_cells; 110 + 111 + ret = get_addr_size_cells(&addr_cells, &size_cells); 112 + if (ret) 113 + return ret; 114 + 115 + if (len < 4 * (addr_cells + size_cells)) 116 + return -ENOENT; 117 + 118 + *addr = of_read_number(prop, addr_cells); 119 + *size = of_read_number(prop + 4 * addr_cells, size_cells); 120 + 121 + return 0; 122 + } 123 + 124 + /** 125 + * ima_get_kexec_buffer - get IMA buffer from the previous kernel 126 + * @addr: On successful return, set to point to the buffer contents. 127 + * @size: On successful return, set to the buffer size. 128 + * 129 + * Return: 0 on success, negative errno on error. 130 + */ 131 + int ima_get_kexec_buffer(void **addr, size_t *size) 132 + { 133 + int ret, len; 134 + unsigned long tmp_addr; 135 + size_t tmp_size; 136 + const void *prop; 137 + 138 + if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC)) 139 + return -ENOTSUPP; 140 + 141 + prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len); 142 + if (!prop) 143 + return -ENOENT; 144 + 145 + ret = do_get_kexec_buffer(prop, len, &tmp_addr, &tmp_size); 146 + if (ret) 147 + return ret; 148 + 149 + *addr = __va(tmp_addr); 150 + *size = tmp_size; 151 + 152 + return 0; 153 + } 154 + 155 + /** 156 + * ima_free_kexec_buffer - free memory used by the IMA buffer 157 + */ 158 + int ima_free_kexec_buffer(void) 159 + { 160 + int ret; 161 + unsigned long addr; 162 + size_t size; 163 + struct property *prop; 164 + 165 + if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC)) 166 + return -ENOTSUPP; 167 + 168 + prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL); 169 + if (!prop) 170 + return -ENOENT; 171 + 172 + ret = do_get_kexec_buffer(prop->value, prop->length, &addr, &size); 173 + if (ret) 174 + return ret; 175 + 176 + ret = of_remove_property(of_chosen, prop); 177 + if (ret) 178 + return ret; 179 + 180 + return memblock_free(addr, size); 181 + 182 + } 183 + 184 + /** 185 + * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt 186 + * 187 + * @fdt: Flattened Device Tree to update 188 + * @chosen_node: Offset to the chosen node in the device tree 189 + * 190 + * The IMA measurement buffer is of no use to a subsequent kernel, so we always 191 + * remove it from the device tree. 192 + */ 193 + static void remove_ima_buffer(void *fdt, int chosen_node) 194 + { 195 + int ret, len; 196 + unsigned long addr; 197 + size_t size; 198 + const void *prop; 199 + 200 + if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC)) 201 + return; 202 + 203 + prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len); 204 + if (!prop) 205 + return; 206 + 207 + ret = do_get_kexec_buffer(prop, len, &addr, &size); 208 + fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer"); 209 + if (ret) 210 + return; 211 + 212 + ret = fdt_find_and_del_mem_rsv(fdt, addr, size); 213 + if (!ret) 214 + pr_debug("Removed old IMA buffer reservation.\n"); 215 + } 216 + 217 + #ifdef CONFIG_IMA_KEXEC 218 + /** 219 + * write_number - Convert number to big-endian format 220 + * 221 + * @p: Buffer to write the number to 222 + * @value: Number to convert 223 + * @cells: Number of cells 224 + * 225 + * Return: 0 on success, or negative errno on error. 226 + */ 227 + static int write_number(void *p, u64 value, int cells) 228 + { 229 + if (cells == 1) { 230 + u32 tmp; 231 + 232 + if (value > U32_MAX) 233 + return -EINVAL; 234 + 235 + tmp = cpu_to_be32(value); 236 + memcpy(p, &tmp, sizeof(tmp)); 237 + } else if (cells == 2) { 238 + u64 tmp; 239 + 240 + tmp = cpu_to_be64(value); 241 + memcpy(p, &tmp, sizeof(tmp)); 242 + } else 243 + return -EINVAL; 244 + 245 + return 0; 246 + } 247 + 248 + /** 249 + * setup_ima_buffer - add IMA buffer information to the fdt 250 + * @image: kexec image being loaded. 251 + * @fdt: Flattened device tree for the next kernel. 252 + * @chosen_node: Offset to the chosen node. 253 + * 254 + * Return: 0 on success, or negative errno on error. 255 + */ 256 + static int setup_ima_buffer(const struct kimage *image, void *fdt, 257 + int chosen_node) 258 + { 259 + int ret, addr_cells, size_cells, entry_size; 260 + u8 value[16]; 261 + 262 + if (!image->ima_buffer_size) 263 + return 0; 264 + 265 + ret = get_addr_size_cells(&addr_cells, &size_cells); 266 + if (ret) 267 + return ret; 268 + 269 + entry_size = 4 * (addr_cells + size_cells); 270 + 271 + if (entry_size > sizeof(value)) 272 + return -EINVAL; 273 + 274 + ret = write_number(value, image->ima_buffer_addr, addr_cells); 275 + if (ret) 276 + return ret; 277 + 278 + ret = write_number(value + 4 * addr_cells, image->ima_buffer_size, 279 + size_cells); 280 + if (ret) 281 + return ret; 282 + 283 + ret = fdt_setprop(fdt, chosen_node, "linux,ima-kexec-buffer", value, 284 + entry_size); 285 + if (ret < 0) 286 + return -EINVAL; 287 + 288 + ret = fdt_add_mem_rsv(fdt, image->ima_buffer_addr, 289 + image->ima_buffer_size); 290 + if (ret) 291 + return -EINVAL; 292 + 293 + pr_debug("IMA buffer at 0x%llx, size = 0x%zx\n", 294 + image->ima_buffer_addr, image->ima_buffer_size); 295 + 296 + return 0; 297 + } 298 + #else /* CONFIG_IMA_KEXEC */ 299 + static inline int setup_ima_buffer(const struct kimage *image, void *fdt, 300 + int chosen_node) 301 + { 302 + return 0; 303 + } 304 + #endif /* CONFIG_IMA_KEXEC */ 72 305 73 306 /* 74 307 * of_kexec_alloc_and_setup_fdt - Alloc and setup a new Flattened Device Tree ··· 489 254 } 490 255 491 256 ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0); 257 + if (ret) 258 + goto out; 259 + 260 + remove_ima_buffer(fdt, chosen_node); 261 + ret = setup_ima_buffer(image, fdt, fdt_path_offset(fdt, "/chosen")); 492 262 493 263 out: 494 264 if (ret) {
+2
include/linux/of.h
··· 565 565 unsigned long initrd_load_addr, 566 566 unsigned long initrd_len, 567 567 const char *cmdline, size_t extra_fdt_size); 568 + int ima_get_kexec_buffer(void **addr, size_t *size); 569 + int ima_free_kexec_buffer(void); 568 570 #else /* CONFIG_OF */ 569 571 570 572 static inline void of_core_init(void)
-4
security/integrity/ima/ima.h
··· 24 24 25 25 #include "../integrity.h" 26 26 27 - #ifdef CONFIG_HAVE_IMA_KEXEC 28 - #include <asm/ima.h> 29 - #endif 30 - 31 27 enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN, 32 28 IMA_SHOW_BINARY_OLD_STRING_FMT, IMA_SHOW_ASCII }; 33 29 enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
+1
security/integrity/ima/ima_kexec.c
··· 10 10 #include <linux/seq_file.h> 11 11 #include <linux/vmalloc.h> 12 12 #include <linux/kexec.h> 13 + #include <linux/of.h> 13 14 #include "ima.h" 14 15 15 16 #ifdef CONFIG_IMA_KEXEC