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