]> Git Repo - u-boot.git/blob - boot/vbe_request.c
Merge patch series "automatically add /chosen/kaslr-seed and deduplicate code"
[u-boot.git] / boot / vbe_request.c
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 <[email protected]>
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
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
74 static int vbe_req_random_seed(ofnode node, struct vbe_result *result)
75 {
76         return handle_random_req(node, 0, result);
77 }
78
79 static int vbe_req_aslr_move(ofnode node, struct vbe_result *result)
80 {
81         return -ENOTSUPP;
82 }
83
84 static int vbe_req_aslr_rand(ofnode node, struct vbe_result *result)
85 {
86         return handle_random_req(node, 4, result);
87 }
88
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
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  */
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);
This page took 0.038268 seconds and 4 git commands to generate.