blob: a1350c1a706ea8f234e0015c4757b1a370d5b0b4 [file] [log] [blame]
Simon Glass8aaacd62022-10-11 09:47:18 -06001// SPDX-License-Identifier: GPL-2.0
2/*
Simon Glass98bedf42022-10-20 18:23:05 -06003 * Verified Boot for Embedded (VBE) OS request (device tree fixup) functions
Simon Glass8aaacd62022-10-11 09:47:18 -06004 *
5 * Copyright 2022 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
9#define LOG_CATEGORY LOGC_BOOT
10
Simon Glass8aaacd62022-10-11 09:47:18 -060011#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
Marek Vasut591257b2024-04-26 01:02:07 +020038 if (!CONFIG_IS_ENABLED(DM_RNG))
Simon Glass8aaacd62022-10-11 09:47:18 -060039 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);
Simon Glass24797092023-09-26 08:14:37 -0600189 ret = ofnode_copy_props(dest, node);
Simon Glass8aaacd62022-10-11 09:47:18 -0600190 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;
Simon Glassc3a148f2022-10-20 18:23:06 -0600197 log_warning("Failed to process VBE request %s (err=%d)\n",
198 ofnode_get_name(dest), ret);
Simon Glass8aaacd62022-10-11 09:47:18 -0600199 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}
Simon Glass6c4cad72023-08-21 21:16:57 -0600232EVENT_SPY_FULL(EVT_FT_FIXUP, bootmeth_vbe_ft_fixup);