kexec.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2020 Arm Limited
  4. *
  5. * Based on arch/arm64/kernel/machine_kexec_file.c:
  6. * Copyright (C) 2018 Linaro Limited
  7. *
  8. * And arch/powerpc/kexec/file_load.c:
  9. * Copyright (C) 2016 IBM Corporation
  10. */
  11. #include <linux/ima.h>
  12. #include <linux/kernel.h>
  13. #include <linux/kexec.h>
  14. #include <linux/memblock.h>
  15. #include <linux/libfdt.h>
  16. #include <linux/of.h>
  17. #include <linux/of_fdt.h>
  18. #include <linux/random.h>
  19. #include <linux/slab.h>
  20. #include <linux/types.h>
  21. #define RNG_SEED_SIZE 128
  22. /*
  23. * Additional space needed for the FDT buffer so that we can add initrd,
  24. * bootargs, kaslr-seed, rng-seed, useable-memory-range and elfcorehdr.
  25. */
  26. #define FDT_EXTRA_SPACE 0x1000
  27. /**
  28. * fdt_find_and_del_mem_rsv - delete memory reservation with given address and size
  29. *
  30. * @fdt: Flattened device tree for the current kernel.
  31. * @start: Starting address of the reserved memory.
  32. * @size: Size of the reserved memory.
  33. *
  34. * Return: 0 on success, or negative errno on error.
  35. */
  36. static int fdt_find_and_del_mem_rsv(void *fdt, unsigned long start, unsigned long size)
  37. {
  38. int i, ret, num_rsvs = fdt_num_mem_rsv(fdt);
  39. for (i = 0; i < num_rsvs; i++) {
  40. u64 rsv_start, rsv_size;
  41. ret = fdt_get_mem_rsv(fdt, i, &rsv_start, &rsv_size);
  42. if (ret) {
  43. pr_err("Malformed device tree.\n");
  44. return -EINVAL;
  45. }
  46. if (rsv_start == start && rsv_size == size) {
  47. ret = fdt_del_mem_rsv(fdt, i);
  48. if (ret) {
  49. pr_err("Error deleting device tree reservation.\n");
  50. return -EINVAL;
  51. }
  52. return 0;
  53. }
  54. }
  55. return -ENOENT;
  56. }
  57. /**
  58. * get_addr_size_cells - Get address and size of root node
  59. *
  60. * @addr_cells: Return address of the root node
  61. * @size_cells: Return size of the root node
  62. *
  63. * Return: 0 on success, or negative errno on error.
  64. */
  65. static int get_addr_size_cells(int *addr_cells, int *size_cells)
  66. {
  67. struct device_node *root;
  68. root = of_find_node_by_path("/");
  69. if (!root)
  70. return -EINVAL;
  71. *addr_cells = of_n_addr_cells(root);
  72. *size_cells = of_n_size_cells(root);
  73. of_node_put(root);
  74. return 0;
  75. }
  76. /**
  77. * do_get_kexec_buffer - Get address and size of device tree property
  78. *
  79. * @prop: Device tree property
  80. * @len: Size of @prop
  81. * @addr: Return address of the node
  82. * @size: Return size of the node
  83. *
  84. * Return: 0 on success, or negative errno on error.
  85. */
  86. static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr,
  87. size_t *size)
  88. {
  89. int ret, addr_cells, size_cells;
  90. ret = get_addr_size_cells(&addr_cells, &size_cells);
  91. if (ret)
  92. return ret;
  93. if (len < 4 * (addr_cells + size_cells))
  94. return -ENOENT;
  95. *addr = of_read_number(prop, addr_cells);
  96. *size = of_read_number(prop + 4 * addr_cells, size_cells);
  97. return 0;
  98. }
  99. #ifdef CONFIG_HAVE_IMA_KEXEC
  100. /**
  101. * ima_get_kexec_buffer - get IMA buffer from the previous kernel
  102. * @addr: On successful return, set to point to the buffer contents.
  103. * @size: On successful return, set to the buffer size.
  104. *
  105. * Return: 0 on success, negative errno on error.
  106. */
  107. int __init ima_get_kexec_buffer(void **addr, size_t *size)
  108. {
  109. int ret, len;
  110. unsigned long tmp_addr;
  111. size_t tmp_size;
  112. const void *prop;
  113. prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len);
  114. if (!prop)
  115. return -ENOENT;
  116. ret = do_get_kexec_buffer(prop, len, &tmp_addr, &tmp_size);
  117. if (ret)
  118. return ret;
  119. /* Do some sanity on the returned size for the ima-kexec buffer */
  120. if (!tmp_size)
  121. return -ENOENT;
  122. ret = ima_validate_range(tmp_addr, tmp_size);
  123. if (ret)
  124. return ret;
  125. *addr = __va(tmp_addr);
  126. *size = tmp_size;
  127. return 0;
  128. }
  129. /**
  130. * ima_free_kexec_buffer - free memory used by the IMA buffer
  131. */
  132. int __init ima_free_kexec_buffer(void)
  133. {
  134. int ret;
  135. unsigned long addr;
  136. size_t size;
  137. struct property *prop;
  138. prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL);
  139. if (!prop)
  140. return -ENOENT;
  141. ret = do_get_kexec_buffer(prop->value, prop->length, &addr, &size);
  142. if (ret)
  143. return ret;
  144. ret = of_remove_property(of_chosen, prop);
  145. if (ret)
  146. return ret;
  147. memblock_free_late(addr, size);
  148. return 0;
  149. }
  150. #endif
  151. /**
  152. * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
  153. *
  154. * @fdt: Flattened Device Tree to update
  155. * @chosen_node: Offset to the chosen node in the device tree
  156. *
  157. * The IMA measurement buffer is of no use to a subsequent kernel, so we always
  158. * remove it from the device tree.
  159. */
  160. static void remove_ima_buffer(void *fdt, int chosen_node)
  161. {
  162. int ret, len;
  163. unsigned long addr;
  164. size_t size;
  165. const void *prop;
  166. if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC))
  167. return;
  168. prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len);
  169. if (!prop)
  170. return;
  171. ret = do_get_kexec_buffer(prop, len, &addr, &size);
  172. fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer");
  173. if (ret)
  174. return;
  175. ret = fdt_find_and_del_mem_rsv(fdt, addr, size);
  176. if (!ret)
  177. pr_debug("Removed old IMA buffer reservation.\n");
  178. }
  179. #ifdef CONFIG_IMA_KEXEC
  180. /**
  181. * setup_ima_buffer - add IMA buffer information to the fdt
  182. * @image: kexec image being loaded.
  183. * @fdt: Flattened device tree for the next kernel.
  184. * @chosen_node: Offset to the chosen node.
  185. *
  186. * Return: 0 on success, or negative errno on error.
  187. */
  188. static int setup_ima_buffer(const struct kimage *image, void *fdt,
  189. int chosen_node)
  190. {
  191. int ret;
  192. if (!image->ima_buffer_size)
  193. return 0;
  194. ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,
  195. "linux,ima-kexec-buffer",
  196. image->ima_buffer_addr,
  197. image->ima_buffer_size);
  198. if (ret < 0)
  199. return -EINVAL;
  200. ret = fdt_add_mem_rsv(fdt, image->ima_buffer_addr,
  201. image->ima_buffer_size);
  202. if (ret)
  203. return -EINVAL;
  204. pr_debug("IMA buffer at 0x%llx, size = 0x%zx\n",
  205. image->ima_buffer_addr, image->ima_buffer_size);
  206. return 0;
  207. }
  208. #else /* CONFIG_IMA_KEXEC */
  209. static inline int setup_ima_buffer(const struct kimage *image, void *fdt,
  210. int chosen_node)
  211. {
  212. return 0;
  213. }
  214. #endif /* CONFIG_IMA_KEXEC */
  215. static int kho_add_chosen(const struct kimage *image, void *fdt, int chosen_node)
  216. {
  217. int ret = 0;
  218. #ifdef CONFIG_KEXEC_HANDOVER
  219. phys_addr_t fdt_mem = 0;
  220. phys_addr_t fdt_len = 0;
  221. phys_addr_t scratch_mem = 0;
  222. phys_addr_t scratch_len = 0;
  223. ret = fdt_delprop(fdt, chosen_node, "linux,kho-fdt");
  224. if (ret && ret != -FDT_ERR_NOTFOUND)
  225. return ret;
  226. ret = fdt_delprop(fdt, chosen_node, "linux,kho-scratch");
  227. if (ret && ret != -FDT_ERR_NOTFOUND)
  228. return ret;
  229. if (!image->kho.fdt || !image->kho.scratch)
  230. return 0;
  231. fdt_mem = image->kho.fdt;
  232. fdt_len = PAGE_SIZE;
  233. scratch_mem = image->kho.scratch->mem;
  234. scratch_len = image->kho.scratch->bufsz;
  235. pr_debug("Adding kho metadata to DT");
  236. ret = fdt_appendprop_addrrange(fdt, 0, chosen_node, "linux,kho-fdt",
  237. fdt_mem, fdt_len);
  238. if (ret)
  239. return ret;
  240. ret = fdt_appendprop_addrrange(fdt, 0, chosen_node, "linux,kho-scratch",
  241. scratch_mem, scratch_len);
  242. #endif /* CONFIG_KEXEC_HANDOVER */
  243. return ret;
  244. }
  245. /*
  246. * of_kexec_alloc_and_setup_fdt - Alloc and setup a new Flattened Device Tree
  247. *
  248. * @image: kexec image being loaded.
  249. * @initrd_load_addr: Address where the next initrd will be loaded.
  250. * @initrd_len: Size of the next initrd, or 0 if there will be none.
  251. * @cmdline: Command line for the next kernel, or NULL if there will
  252. * be none.
  253. * @extra_fdt_size: Additional size for the new FDT buffer.
  254. *
  255. * Return: fdt on success, or NULL errno on error.
  256. */
  257. void *of_kexec_alloc_and_setup_fdt(const struct kimage *image,
  258. unsigned long initrd_load_addr,
  259. unsigned long initrd_len,
  260. const char *cmdline, size_t extra_fdt_size)
  261. {
  262. void *fdt;
  263. int ret, chosen_node, len;
  264. const void *prop;
  265. size_t fdt_size;
  266. fdt_size = fdt_totalsize(initial_boot_params) +
  267. (cmdline ? strlen(cmdline) : 0) +
  268. FDT_EXTRA_SPACE +
  269. extra_fdt_size;
  270. fdt = kvmalloc(fdt_size, GFP_KERNEL);
  271. if (!fdt)
  272. return NULL;
  273. ret = fdt_open_into(initial_boot_params, fdt, fdt_size);
  274. if (ret < 0) {
  275. pr_err("Error %d setting up the new device tree.\n", ret);
  276. goto out;
  277. }
  278. /* Remove memory reservation for the current device tree. */
  279. ret = fdt_find_and_del_mem_rsv(fdt, initial_boot_params_pa,
  280. fdt_totalsize(initial_boot_params));
  281. if (ret == -EINVAL) {
  282. pr_err("Error removing memory reservation.\n");
  283. goto out;
  284. }
  285. chosen_node = fdt_path_offset(fdt, "/chosen");
  286. if (chosen_node == -FDT_ERR_NOTFOUND)
  287. chosen_node = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"),
  288. "chosen");
  289. if (chosen_node < 0) {
  290. ret = chosen_node;
  291. goto out;
  292. }
  293. ret = fdt_delprop(fdt, chosen_node, "linux,elfcorehdr");
  294. if (ret && ret != -FDT_ERR_NOTFOUND)
  295. goto out;
  296. ret = fdt_delprop(fdt, chosen_node, "linux,usable-memory-range");
  297. if (ret && ret != -FDT_ERR_NOTFOUND)
  298. goto out;
  299. /* Did we boot using an initrd? */
  300. prop = fdt_getprop(fdt, chosen_node, "linux,initrd-start", &len);
  301. if (prop) {
  302. u64 tmp_start, tmp_end, tmp_size;
  303. tmp_start = of_read_number(prop, len / 4);
  304. prop = fdt_getprop(fdt, chosen_node, "linux,initrd-end", &len);
  305. if (!prop) {
  306. ret = -EINVAL;
  307. goto out;
  308. }
  309. tmp_end = of_read_number(prop, len / 4);
  310. /*
  311. * kexec reserves exact initrd size, while firmware may
  312. * reserve a multiple of PAGE_SIZE, so check for both.
  313. */
  314. tmp_size = tmp_end - tmp_start;
  315. ret = fdt_find_and_del_mem_rsv(fdt, tmp_start, tmp_size);
  316. if (ret == -ENOENT)
  317. ret = fdt_find_and_del_mem_rsv(fdt, tmp_start,
  318. round_up(tmp_size, PAGE_SIZE));
  319. if (ret == -EINVAL)
  320. goto out;
  321. }
  322. /* add initrd-* */
  323. if (initrd_load_addr) {
  324. ret = fdt_setprop_u64(fdt, chosen_node, "linux,initrd-start",
  325. initrd_load_addr);
  326. if (ret)
  327. goto out;
  328. ret = fdt_setprop_u64(fdt, chosen_node, "linux,initrd-end",
  329. initrd_load_addr + initrd_len);
  330. if (ret)
  331. goto out;
  332. ret = fdt_add_mem_rsv(fdt, initrd_load_addr, initrd_len);
  333. if (ret)
  334. goto out;
  335. } else {
  336. ret = fdt_delprop(fdt, chosen_node, "linux,initrd-start");
  337. if (ret && (ret != -FDT_ERR_NOTFOUND))
  338. goto out;
  339. ret = fdt_delprop(fdt, chosen_node, "linux,initrd-end");
  340. if (ret && (ret != -FDT_ERR_NOTFOUND))
  341. goto out;
  342. }
  343. if (image->type == KEXEC_TYPE_CRASH) {
  344. /* add linux,elfcorehdr */
  345. ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,
  346. "linux,elfcorehdr", image->elf_load_addr,
  347. image->elf_headers_sz);
  348. if (ret)
  349. goto out;
  350. /*
  351. * Avoid elfcorehdr from being stomped on in kdump kernel by
  352. * setting up memory reserve map.
  353. */
  354. ret = fdt_add_mem_rsv(fdt, image->elf_load_addr,
  355. image->elf_headers_sz);
  356. if (ret)
  357. goto out;
  358. #ifdef CONFIG_CRASH_DUMP
  359. /* add linux,usable-memory-range */
  360. ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,
  361. "linux,usable-memory-range", crashk_res.start,
  362. crashk_res.end - crashk_res.start + 1);
  363. if (ret)
  364. goto out;
  365. if (crashk_low_res.end) {
  366. ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,
  367. "linux,usable-memory-range",
  368. crashk_low_res.start,
  369. crashk_low_res.end - crashk_low_res.start + 1);
  370. if (ret)
  371. goto out;
  372. }
  373. #endif
  374. }
  375. /* Add kho metadata if this is a KHO image */
  376. ret = kho_add_chosen(image, fdt, chosen_node);
  377. if (ret)
  378. goto out;
  379. /* add bootargs */
  380. if (cmdline) {
  381. ret = fdt_setprop_string(fdt, chosen_node, "bootargs", cmdline);
  382. if (ret)
  383. goto out;
  384. } else {
  385. ret = fdt_delprop(fdt, chosen_node, "bootargs");
  386. if (ret && (ret != -FDT_ERR_NOTFOUND))
  387. goto out;
  388. }
  389. /* add kaslr-seed */
  390. ret = fdt_delprop(fdt, chosen_node, "kaslr-seed");
  391. if (ret == -FDT_ERR_NOTFOUND)
  392. ret = 0;
  393. else if (ret)
  394. goto out;
  395. if (rng_is_initialized()) {
  396. u64 seed = get_random_u64();
  397. ret = fdt_setprop_u64(fdt, chosen_node, "kaslr-seed", seed);
  398. if (ret)
  399. goto out;
  400. } else {
  401. pr_notice("RNG is not initialised: omitting \"%s\" property\n",
  402. "kaslr-seed");
  403. }
  404. /* add rng-seed */
  405. if (rng_is_initialized()) {
  406. void *rng_seed;
  407. ret = fdt_setprop_placeholder(fdt, chosen_node, "rng-seed",
  408. RNG_SEED_SIZE, &rng_seed);
  409. if (ret)
  410. goto out;
  411. get_random_bytes(rng_seed, RNG_SEED_SIZE);
  412. } else {
  413. pr_notice("RNG is not initialised: omitting \"%s\" property\n",
  414. "rng-seed");
  415. }
  416. ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0);
  417. if (ret)
  418. goto out;
  419. remove_ima_buffer(fdt, chosen_node);
  420. ret = setup_ima_buffer(image, fdt, fdt_path_offset(fdt, "/chosen"));
  421. out:
  422. if (ret) {
  423. kvfree(fdt);
  424. fdt = NULL;
  425. }
  426. return fdt;
  427. }