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 
23 struct vbe_result {
24 	int errnum;
25 	char err_str[VBE_ERR_STR_LEN];
26 };
27 
28 typedef int (*vbe_req_func)(ofnode node, struct vbe_result *result);
29 
handle_random_req(ofnode node,int default_size,struct vbe_result * result)30 static 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 
vbe_req_random_seed(ofnode node,struct vbe_result * result)74 static int vbe_req_random_seed(ofnode node, struct vbe_result *result)
75 {
76 	return handle_random_req(node, 0, result);
77 }
78 
vbe_req_aslr_move(ofnode node,struct vbe_result * result)79 static int vbe_req_aslr_move(ofnode node, struct vbe_result *result)
80 {
81 	return -ENOTSUPP;
82 }
83 
vbe_req_aslr_rand(ofnode node,struct vbe_result * result)84 static int vbe_req_aslr_rand(ofnode node, struct vbe_result *result)
85 {
86 	return handle_random_req(node, 4, result);
87 }
88 
vbe_req_efi_runtime_rand(ofnode node,struct vbe_result * result)89 static int vbe_req_efi_runtime_rand(ofnode node, struct vbe_result *result)
90 {
91 	return handle_random_req(node, 4, result);
92 }
93 
94 static 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 
vbe_process_request(ofnode node,struct vbe_result * result)112 static 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  */
bootmeth_vbe_ft_fixup(void * ctx,struct event * event)151 static 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 }
232 EVENT_SPY_FULL(EVT_FT_FIXUP, bootmeth_vbe_ft_fixup);
233