ima_kexec.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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. #include <linux/slab.h>
  13. #include <linux/kexec.h>
  14. #include <linux/of.h>
  15. #include <linux/memblock.h>
  16. #include <linux/libfdt.h>
  17. static int get_addr_size_cells(int *addr_cells, int *size_cells)
  18. {
  19. struct device_node *root;
  20. root = of_find_node_by_path("/");
  21. if (!root)
  22. return -EINVAL;
  23. *addr_cells = of_n_addr_cells(root);
  24. *size_cells = of_n_size_cells(root);
  25. of_node_put(root);
  26. return 0;
  27. }
  28. static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr,
  29. size_t *size)
  30. {
  31. int ret, addr_cells, size_cells;
  32. ret = get_addr_size_cells(&addr_cells, &size_cells);
  33. if (ret)
  34. return ret;
  35. if (len < 4 * (addr_cells + size_cells))
  36. return -ENOENT;
  37. *addr = of_read_number(prop, addr_cells);
  38. *size = of_read_number(prop + 4 * addr_cells, size_cells);
  39. return 0;
  40. }
  41. /**
  42. * ima_get_kexec_buffer - get IMA buffer from the previous kernel
  43. * @addr: On successful return, set to point to the buffer contents.
  44. * @size: On successful return, set to the buffer size.
  45. *
  46. * Return: 0 on success, negative errno on error.
  47. */
  48. int ima_get_kexec_buffer(void **addr, size_t *size)
  49. {
  50. int ret, len;
  51. unsigned long tmp_addr;
  52. size_t tmp_size;
  53. const void *prop;
  54. prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len);
  55. if (!prop)
  56. return -ENOENT;
  57. ret = do_get_kexec_buffer(prop, len, &tmp_addr, &tmp_size);
  58. if (ret)
  59. return ret;
  60. *addr = __va(tmp_addr);
  61. *size = tmp_size;
  62. return 0;
  63. }
  64. /**
  65. * ima_free_kexec_buffer - free memory used by the IMA buffer
  66. */
  67. int ima_free_kexec_buffer(void)
  68. {
  69. int ret;
  70. unsigned long addr;
  71. size_t size;
  72. struct property *prop;
  73. prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL);
  74. if (!prop)
  75. return -ENOENT;
  76. ret = do_get_kexec_buffer(prop->value, prop->length, &addr, &size);
  77. if (ret)
  78. return ret;
  79. ret = of_remove_property(of_chosen, prop);
  80. if (ret)
  81. return ret;
  82. return memblock_free(addr, size);
  83. }
  84. /**
  85. * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
  86. *
  87. * The IMA measurement buffer is of no use to a subsequent kernel, so we always
  88. * remove it from the device tree.
  89. */
  90. void remove_ima_buffer(void *fdt, int chosen_node)
  91. {
  92. int ret, len;
  93. unsigned long addr;
  94. size_t size;
  95. const void *prop;
  96. prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len);
  97. if (!prop)
  98. return;
  99. ret = do_get_kexec_buffer(prop, len, &addr, &size);
  100. fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer");
  101. if (ret)
  102. return;
  103. ret = delete_fdt_mem_rsv(fdt, addr, size);
  104. if (!ret)
  105. pr_debug("Removed old IMA buffer reservation.\n");
  106. }
  107. #ifdef CONFIG_IMA_KEXEC
  108. /**
  109. * arch_ima_add_kexec_buffer - do arch-specific steps to add the IMA buffer
  110. *
  111. * Architectures should use this function to pass on the IMA buffer
  112. * information to the next kernel.
  113. *
  114. * Return: 0 on success, negative errno on error.
  115. */
  116. int arch_ima_add_kexec_buffer(struct kimage *image, unsigned long load_addr,
  117. size_t size)
  118. {
  119. image->arch.ima_buffer_addr = load_addr;
  120. image->arch.ima_buffer_size = size;
  121. return 0;
  122. }
  123. static int write_number(void *p, u64 value, int cells)
  124. {
  125. if (cells == 1) {
  126. u32 tmp;
  127. if (value > U32_MAX)
  128. return -EINVAL;
  129. tmp = cpu_to_be32(value);
  130. memcpy(p, &tmp, sizeof(tmp));
  131. } else if (cells == 2) {
  132. u64 tmp;
  133. tmp = cpu_to_be64(value);
  134. memcpy(p, &tmp, sizeof(tmp));
  135. } else
  136. return -EINVAL;
  137. return 0;
  138. }
  139. /**
  140. * setup_ima_buffer - add IMA buffer information to the fdt
  141. * @image: kexec image being loaded.
  142. * @fdt: Flattened device tree for the next kernel.
  143. * @chosen_node: Offset to the chosen node.
  144. *
  145. * Return: 0 on success, or negative errno on error.
  146. */
  147. int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node)
  148. {
  149. int ret, addr_cells, size_cells, entry_size;
  150. u8 value[16];
  151. remove_ima_buffer(fdt, chosen_node);
  152. if (!image->arch.ima_buffer_size)
  153. return 0;
  154. ret = get_addr_size_cells(&addr_cells, &size_cells);
  155. if (ret)
  156. return ret;
  157. entry_size = 4 * (addr_cells + size_cells);
  158. if (entry_size > sizeof(value))
  159. return -EINVAL;
  160. ret = write_number(value, image->arch.ima_buffer_addr, addr_cells);
  161. if (ret)
  162. return ret;
  163. ret = write_number(value + 4 * addr_cells, image->arch.ima_buffer_size,
  164. size_cells);
  165. if (ret)
  166. return ret;
  167. ret = fdt_setprop(fdt, chosen_node, "linux,ima-kexec-buffer", value,
  168. entry_size);
  169. if (ret < 0)
  170. return -EINVAL;
  171. ret = fdt_add_mem_rsv(fdt, image->arch.ima_buffer_addr,
  172. image->arch.ima_buffer_size);
  173. if (ret)
  174. return -EINVAL;
  175. pr_debug("IMA buffer at 0x%llx, size = 0x%zx\n",
  176. image->arch.ima_buffer_addr, image->arch.ima_buffer_size);
  177. return 0;
  178. }
  179. #endif /* CONFIG_IMA_KEXEC */