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 <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 
24 struct vbe_result {
25 	int errnum;
26 	char err_str[VBE_ERR_STR_LEN];
27 };
28 
29 typedef int (*vbe_req_func)(ofnode node, struct vbe_result *result);
30 
handle_random_req(ofnode node,int default_size,struct vbe_result * result)31 static 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 
39 	if (!IS_ENABLED(CONFIG_DM_RNG))
40 		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 
vbe_req_random_seed(ofnode node,struct vbe_result * result)75 static int vbe_req_random_seed(ofnode node, struct vbe_result *result)
76 {
77 	return handle_random_req(node, 0, result);
78 }
79 
vbe_req_aslr_move(ofnode node,struct vbe_result * result)80 static int vbe_req_aslr_move(ofnode node, struct vbe_result *result)
81 {
82 	return -ENOTSUPP;
83 }
84 
vbe_req_aslr_rand(ofnode node,struct vbe_result * result)85 static int vbe_req_aslr_rand(ofnode node, struct vbe_result *result)
86 {
87 	return handle_random_req(node, 4, result);
88 }
89 
vbe_req_efi_runtime_rand(ofnode node,struct vbe_result * result)90 static int vbe_req_efi_runtime_rand(ofnode node, struct vbe_result *result)
91 {
92 	return handle_random_req(node, 4, result);
93 }
94 
95 static 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 
vbe_process_request(ofnode node,struct vbe_result * result)113 static 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  */
bootmeth_vbe_ft_fixup(void * ctx,struct event * event)152 static 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;
198 			log_warning("Failed to process VBE request %s (err=%d)\n",
199 				    ofnode_get_name(dest), ret);
200 			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 }
233 EVENT_SPY(EVT_FT_FIXUP, bootmeth_vbe_ft_fixup);
234