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 15static 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 31static 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 */ 56int 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 */ 80int 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 */ 109void 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/** 132 * arch_ima_add_kexec_buffer - do arch-specific steps to add the IMA buffer 133 * 134 * Architectures should use this function to pass on the IMA buffer 135 * information to the next kernel. 136 * 137 * Return: 0 on success, negative errno on error. 138 */ 139int arch_ima_add_kexec_buffer(struct kimage *image, unsigned long load_addr, 140 size_t size) 141{ 142 image->arch.ima_buffer_addr = load_addr; 143 image->arch.ima_buffer_size = size; 144 145 return 0; 146} 147 148static int write_number(void *p, u64 value, int cells) 149{ 150 if (cells == 1) { 151 u32 tmp; 152 153 if (value > U32_MAX) 154 return -EINVAL; 155 156 tmp = cpu_to_be32(value); 157 memcpy(p, &tmp, sizeof(tmp)); 158 } else if (cells == 2) { 159 u64 tmp; 160 161 tmp = cpu_to_be64(value); 162 memcpy(p, &tmp, sizeof(tmp)); 163 } else 164 return -EINVAL; 165 166 return 0; 167} 168 169/** 170 * setup_ima_buffer - add IMA buffer information to the fdt 171 * @image: kexec image being loaded. 172 * @fdt: Flattened device tree for the next kernel. 173 * @chosen_node: Offset to the chosen node. 174 * 175 * Return: 0 on success, or negative errno on error. 176 */ 177int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node) 178{ 179 int ret, addr_cells, size_cells, entry_size; 180 u8 value[16]; 181 182 remove_ima_buffer(fdt, chosen_node); 183 if (!image->arch.ima_buffer_size) 184 return 0; 185 186 ret = get_addr_size_cells(&addr_cells, &size_cells); 187 if (ret) 188 return ret; 189 190 entry_size = 4 * (addr_cells + size_cells); 191 192 if (entry_size > sizeof(value)) 193 return -EINVAL; 194 195 ret = write_number(value, image->arch.ima_buffer_addr, addr_cells); 196 if (ret) 197 return ret; 198 199 ret = write_number(value + 4 * addr_cells, image->arch.ima_buffer_size, 200 size_cells); 201 if (ret) 202 return ret; 203 204 ret = fdt_setprop(fdt, chosen_node, "linux,ima-kexec-buffer", value, 205 entry_size); 206 if (ret < 0) 207 return -EINVAL; 208 209 ret = fdt_add_mem_rsv(fdt, image->arch.ima_buffer_addr, 210 image->arch.ima_buffer_size); 211 if (ret) 212 return -EINVAL; 213 214 pr_debug("IMA buffer at 0x%llx, size = 0x%zx\n", 215 image->arch.ima_buffer_addr, image->arch.ima_buffer_size); 216 217 return 0; 218} 219#endif /* CONFIG_IMA_KEXEC */ 220