root/arch/powerpc/kernel/ima_kexec.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_addr_size_cells
  2. do_get_kexec_buffer
  3. ima_get_kexec_buffer
  4. ima_free_kexec_buffer
  5. remove_ima_buffer
  6. arch_ima_add_kexec_buffer
  7. write_number
  8. setup_ima_buffer

   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 /**
 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  */
 139 int 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 
 148 static 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  */
 177 int 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 */

/* [<][>][^][v][top][bottom][index][help] */