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