vbe_request.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Verified Boot for Embedded (VBE) OS request (device tree fixup) functions
  4. *
  5. * Copyright 2022 Google LLC
  6. * Written by Simon Glass <sjg@chromium.org>
  7. */
  8. #define LOG_CATEGORY LOGC_BOOT
  9. #include <common.h>
  10. #include <dm.h>
  11. #include <event.h>
  12. #include <image.h>
  13. #include <malloc.h>
  14. #include <rng.h>
  15. #include <dm/ofnode.h>
  16. #define VBE_PREFIX "vbe,"
  17. #define VBE_PREFIX_LEN (sizeof(VBE_PREFIX) - 1)
  18. #define VBE_ERR_STR_LEN 128
  19. #define VBE_MAX_RAND_SIZE 256
  20. struct vbe_result {
  21. int errnum;
  22. char err_str[VBE_ERR_STR_LEN];
  23. };
  24. typedef int (*vbe_req_func)(ofnode node, struct vbe_result *result);
  25. static int handle_random_req(ofnode node, int default_size,
  26. struct vbe_result *result)
  27. {
  28. char buf[VBE_MAX_RAND_SIZE];
  29. struct udevice *dev;
  30. u32 size;
  31. int ret;
  32. if (!IS_ENABLED(CONFIG_DM_RNG))
  33. return -ENOTSUPP;
  34. if (ofnode_read_u32(node, "vbe,size", &size)) {
  35. if (!default_size) {
  36. snprintf(result->err_str, VBE_ERR_STR_LEN,
  37. "Missing vbe,size property");
  38. return log_msg_ret("byt", -EINVAL);
  39. }
  40. size = default_size;
  41. }
  42. if (size > VBE_MAX_RAND_SIZE) {
  43. snprintf(result->err_str, VBE_ERR_STR_LEN,
  44. "vbe,size %#x exceeds max size %#x", size,
  45. VBE_MAX_RAND_SIZE);
  46. return log_msg_ret("siz", -E2BIG);
  47. }
  48. ret = uclass_first_device_err(UCLASS_RNG, &dev);
  49. if (ret) {
  50. snprintf(result->err_str, VBE_ERR_STR_LEN,
  51. "Cannot find random-number device (err=%d)", ret);
  52. return log_msg_ret("wr", ret);
  53. }
  54. ret = dm_rng_read(dev, buf, size);
  55. if (ret) {
  56. snprintf(result->err_str, VBE_ERR_STR_LEN,
  57. "Failed to read random-number device (err=%d)", ret);
  58. return log_msg_ret("rd", ret);
  59. }
  60. ret = ofnode_write_prop(node, "data", buf, size, true);
  61. if (ret)
  62. return log_msg_ret("wr", -EINVAL);
  63. return 0;
  64. }
  65. static int vbe_req_random_seed(ofnode node, struct vbe_result *result)
  66. {
  67. return handle_random_req(node, 0, result);
  68. }
  69. static int vbe_req_aslr_move(ofnode node, struct vbe_result *result)
  70. {
  71. return -ENOTSUPP;
  72. }
  73. static int vbe_req_aslr_rand(ofnode node, struct vbe_result *result)
  74. {
  75. return handle_random_req(node, 4, result);
  76. }
  77. static int vbe_req_efi_runtime_rand(ofnode node, struct vbe_result *result)
  78. {
  79. return handle_random_req(node, 4, result);
  80. }
  81. static struct vbe_req {
  82. const char *compat;
  83. vbe_req_func func;
  84. } vbe_reqs[] = {
  85. /* address space layout randomization - move the OS in memory */
  86. { "aslr-move", vbe_req_aslr_move },
  87. /* provide random data for address space layout randomization */
  88. { "aslr-rand", vbe_req_aslr_rand },
  89. /* provide random data for EFI-runtime-services address */
  90. { "efi-runtime-rand", vbe_req_efi_runtime_rand },
  91. /* generate random data bytes to see the OS's rand generator */
  92. { "random-rand", vbe_req_random_seed },
  93. };
  94. static int vbe_process_request(ofnode node, struct vbe_result *result)
  95. {
  96. const char *compat, *req_name;
  97. int i;
  98. compat = ofnode_read_string(node, "compatible");
  99. if (!compat)
  100. return 0;
  101. if (strlen(compat) <= VBE_PREFIX_LEN ||
  102. strncmp(compat, VBE_PREFIX, VBE_PREFIX_LEN))
  103. return -EINVAL;
  104. req_name = compat + VBE_PREFIX_LEN; /* drop "vbe," prefix */
  105. for (i = 0; i < ARRAY_SIZE(vbe_reqs); i++) {
  106. if (!strcmp(vbe_reqs[i].compat, req_name)) {
  107. int ret;
  108. ret = vbe_reqs[i].func(node, result);
  109. if (ret)
  110. return log_msg_ret("req", ret);
  111. return 0;
  112. }
  113. }
  114. snprintf(result->err_str, VBE_ERR_STR_LEN, "Unknown request: %s",
  115. req_name);
  116. return -ENOTSUPP;
  117. }
  118. /**
  119. * bootmeth_vbe_ft_fixup() - Process VBE OS requests and do device tree fixups
  120. *
  121. * If there are no images provided, this does nothing and returns 0.
  122. *
  123. * @ctx: Context for event
  124. * @event: Event to process
  125. * @return 0 if OK, -ve on error
  126. */
  127. static int bootmeth_vbe_ft_fixup(void *ctx, struct event *event)
  128. {
  129. const struct event_ft_fixup *fixup = &event->data.ft_fixup;
  130. const struct bootm_headers *images = fixup->images;
  131. ofnode parent, dest_parent, root, node;
  132. oftree fit;
  133. if (!images || !images->fit_hdr_os)
  134. return 0;
  135. /* Get the image node with requests in it */
  136. log_debug("fit=%p, noffset=%d\n", images->fit_hdr_os,
  137. images->fit_noffset_os);
  138. fit = oftree_from_fdt(images->fit_hdr_os);
  139. root = oftree_root(fit);
  140. if (of_live_active()) {
  141. log_warning("Cannot fix up live tree\n");
  142. return 0;
  143. }
  144. if (!ofnode_valid(root))
  145. return log_msg_ret("rt", -EINVAL);
  146. parent = noffset_to_ofnode(root, images->fit_noffset_os);
  147. if (!ofnode_valid(parent))
  148. return log_msg_ret("img", -EINVAL);
  149. dest_parent = oftree_path(fixup->tree, "/chosen");
  150. if (!ofnode_valid(dest_parent))
  151. return log_msg_ret("dst", -EINVAL);
  152. ofnode_for_each_subnode(node, parent) {
  153. const char *name = ofnode_get_name(node);
  154. struct vbe_result result;
  155. ofnode dest;
  156. int ret;
  157. log_debug("copy subnode: %s\n", name);
  158. ret = ofnode_add_subnode(dest_parent, name, &dest);
  159. if (ret && ret != -EEXIST)
  160. return log_msg_ret("add", ret);
  161. ret = ofnode_copy_props(node, dest);
  162. if (ret)
  163. return log_msg_ret("cp", ret);
  164. *result.err_str = '\0';
  165. ret = vbe_process_request(dest, &result);
  166. if (ret) {
  167. result.errnum = ret;
  168. log_warning("Failed to process VBE request %s (err=%d)\n",
  169. ofnode_get_name(dest), ret);
  170. if (*result.err_str) {
  171. char *msg = strdup(result.err_str);
  172. if (!msg)
  173. return log_msg_ret("msg", -ENOMEM);
  174. ret = ofnode_write_string(dest, "vbe,error",
  175. msg);
  176. if (ret) {
  177. free(msg);
  178. return log_msg_ret("str", -ENOMEM);
  179. }
  180. }
  181. if (result.errnum) {
  182. ret = ofnode_write_u32(dest, "vbe,errnum",
  183. result.errnum);
  184. if (ret)
  185. return log_msg_ret("num", -ENOMEM);
  186. if (result.errnum != -ENOTSUPP)
  187. return log_msg_ret("pro",
  188. result.errnum);
  189. if (result.errnum == -ENOTSUPP &&
  190. ofnode_read_bool(dest, "vbe,required")) {
  191. log_err("Cannot handle required request: %s\n",
  192. ofnode_get_name(dest));
  193. return log_msg_ret("req",
  194. result.errnum);
  195. }
  196. }
  197. }
  198. }
  199. return 0;
  200. }
  201. EVENT_SPY(EVT_FT_FIXUP, bootmeth_vbe_ft_fixup);