1 /*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * uefi vars device - VarCheckPolicyLibMmiHandler implementation
5 *
6 * variable policy specs:
7 * https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Library/VariablePolicyLib/ReadMe.md
8 */
9 #include "qemu/osdep.h"
10 #include "system/dma.h"
11 #include "migration/vmstate.h"
12
13 #include "hw/uefi/var-service.h"
14 #include "hw/uefi/var-service-api.h"
15 #include "hw/uefi/var-service-edk2.h"
16
17 #include "trace/trace-hw_uefi.h"
18
19 static void calc_policy(uefi_var_policy *pol);
20
uefi_var_policy_post_load(void * opaque,int version_id)21 static int uefi_var_policy_post_load(void *opaque, int version_id)
22 {
23 uefi_var_policy *pol = opaque;
24
25 calc_policy(pol);
26 return 0;
27 }
28
29 const VMStateDescription vmstate_uefi_var_policy = {
30 .name = "uefi-var-policy",
31 .post_load = uefi_var_policy_post_load,
32 .fields = (VMStateField[]) {
33 VMSTATE_UINT32(entry_size, uefi_var_policy),
34 VMSTATE_VBUFFER_ALLOC_UINT32(entry, uefi_var_policy,
35 0, NULL, entry_size),
36 VMSTATE_END_OF_LIST()
37 },
38 };
39
print_policy_entry(variable_policy_entry * pe)40 static void print_policy_entry(variable_policy_entry *pe)
41 {
42 uint16_t *name = (void *)pe + pe->offset_to_name;
43
44 fprintf(stderr, "%s:\n", __func__);
45
46 fprintf(stderr, " name ´");
47 while (*name) {
48 fprintf(stderr, "%c", *name);
49 name++;
50 }
51 fprintf(stderr, "', version=%d.%d, size=%d\n",
52 pe->version >> 16, pe->version & 0xffff, pe->size);
53
54 if (pe->min_size) {
55 fprintf(stderr, " size min=%d\n", pe->min_size);
56 }
57 if (pe->max_size != UINT32_MAX) {
58 fprintf(stderr, " size max=%u\n", pe->max_size);
59 }
60 if (pe->attributes_must_have) {
61 fprintf(stderr, " attr must=0x%x\n", pe->attributes_must_have);
62 }
63 if (pe->attributes_cant_have) {
64 fprintf(stderr, " attr cant=0x%x\n", pe->attributes_cant_have);
65 }
66 if (pe->lock_policy_type) {
67 fprintf(stderr, " lock policy type %d\n", pe->lock_policy_type);
68 }
69 }
70
wildcard_str_equal(uefi_var_policy * pol,uefi_variable * var)71 static gboolean wildcard_str_equal(uefi_var_policy *pol,
72 uefi_variable *var)
73 {
74 return uefi_str_equal_ex(pol->name, pol->name_size,
75 var->name, var->name_size,
76 true);
77 }
78
find_policy(uefi_vars_state * uv,QemuUUID guid,uint16_t * name,uint64_t name_size)79 static uefi_var_policy *find_policy(uefi_vars_state *uv, QemuUUID guid,
80 uint16_t *name, uint64_t name_size)
81 {
82 uefi_var_policy *pol;
83
84 QTAILQ_FOREACH(pol, &uv->var_policies, next) {
85 if (!qemu_uuid_is_equal(&pol->entry->namespace, &guid)) {
86 continue;
87 }
88 if (!uefi_str_equal(pol->name, pol->name_size,
89 name, name_size)) {
90 continue;
91 }
92 return pol;
93 }
94 return NULL;
95 }
96
wildcard_find_policy(uefi_vars_state * uv,uefi_variable * var)97 static uefi_var_policy *wildcard_find_policy(uefi_vars_state *uv,
98 uefi_variable *var)
99 {
100 uefi_var_policy *pol;
101
102 QTAILQ_FOREACH(pol, &uv->var_policies, next) {
103 if (!qemu_uuid_is_equal(&pol->entry->namespace, &var->guid)) {
104 continue;
105 }
106 if (!wildcard_str_equal(pol, var)) {
107 continue;
108 }
109 return pol;
110 }
111 return NULL;
112 }
113
calc_policy(uefi_var_policy * pol)114 static void calc_policy(uefi_var_policy *pol)
115 {
116 variable_policy_entry *pe = pol->entry;
117 unsigned int i;
118
119 pol->name = (void *)pol->entry + pe->offset_to_name;
120 pol->name_size = pe->size - pe->offset_to_name;
121
122 for (i = 0; i < pol->name_size / 2; i++) {
123 if (pol->name[i] == '#') {
124 pol->hashmarks++;
125 }
126 }
127 }
128
uefi_vars_add_policy(uefi_vars_state * uv,variable_policy_entry * pe)129 uefi_var_policy *uefi_vars_add_policy(uefi_vars_state *uv,
130 variable_policy_entry *pe)
131 {
132 uefi_var_policy *pol, *p;
133
134 pol = g_new0(uefi_var_policy, 1);
135 pol->entry = g_malloc(pe->size);
136 memcpy(pol->entry, pe, pe->size);
137 pol->entry_size = pe->size;
138
139 calc_policy(pol);
140
141 /* keep list sorted by priority, add to tail of priority group */
142 QTAILQ_FOREACH(p, &uv->var_policies, next) {
143 if ((p->hashmarks > pol->hashmarks) ||
144 (!p->name_size && pol->name_size)) {
145 QTAILQ_INSERT_BEFORE(p, pol, next);
146 return pol;
147 }
148 }
149
150 QTAILQ_INSERT_TAIL(&uv->var_policies, pol, next);
151 return pol;
152 }
153
uefi_vars_policy_check(uefi_vars_state * uv,uefi_variable * var,gboolean is_newvar)154 efi_status uefi_vars_policy_check(uefi_vars_state *uv,
155 uefi_variable *var,
156 gboolean is_newvar)
157 {
158 uefi_var_policy *pol;
159 variable_policy_entry *pe;
160 variable_lock_on_var_state *lvarstate;
161 uint16_t *lvarname;
162 size_t lvarnamesize;
163 uefi_variable *lvar;
164
165 if (!uv->end_of_dxe) {
166 return EFI_SUCCESS;
167 }
168
169 pol = wildcard_find_policy(uv, var);
170 if (!pol) {
171 return EFI_SUCCESS;
172 }
173 pe = pol->entry;
174
175 uefi_trace_variable(__func__, var->guid, var->name, var->name_size);
176 print_policy_entry(pe);
177
178 if ((var->attributes & pe->attributes_must_have) != pe->attributes_must_have) {
179 trace_uefi_vars_policy_deny("must-have-attr");
180 return EFI_INVALID_PARAMETER;
181 }
182 if ((var->attributes & pe->attributes_cant_have) != 0) {
183 trace_uefi_vars_policy_deny("cant-have-attr");
184 return EFI_INVALID_PARAMETER;
185 }
186
187 if (var->data_size < pe->min_size) {
188 trace_uefi_vars_policy_deny("min-size");
189 return EFI_INVALID_PARAMETER;
190 }
191 if (var->data_size > pe->max_size) {
192 trace_uefi_vars_policy_deny("max-size");
193 return EFI_INVALID_PARAMETER;
194 }
195
196 switch (pe->lock_policy_type) {
197 case VARIABLE_POLICY_TYPE_NO_LOCK:
198 break;
199
200 case VARIABLE_POLICY_TYPE_LOCK_NOW:
201 trace_uefi_vars_policy_deny("lock-now");
202 return EFI_WRITE_PROTECTED;
203
204 case VARIABLE_POLICY_TYPE_LOCK_ON_CREATE:
205 if (!is_newvar) {
206 trace_uefi_vars_policy_deny("lock-on-create");
207 return EFI_WRITE_PROTECTED;
208 }
209 break;
210
211 case VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE:
212 lvarstate = (void *)pol->entry + sizeof(*pe);
213 lvarname = (void *)pol->entry + sizeof(*pe) + sizeof(*lvarstate);
214 lvarnamesize = pe->offset_to_name - sizeof(*pe) - sizeof(*lvarstate);
215
216 uefi_trace_variable(__func__, lvarstate->namespace,
217 lvarname, lvarnamesize);
218 lvar = uefi_vars_find_variable(uv, lvarstate->namespace,
219 lvarname, lvarnamesize);
220 if (lvar && lvar->data_size == 1) {
221 uint8_t *value = lvar->data;
222 if (lvarstate->value == *value) {
223 return EFI_WRITE_PROTECTED;
224 }
225 }
226 break;
227 }
228
229 return EFI_SUCCESS;
230 }
231
uefi_vars_policies_clear(uefi_vars_state * uv)232 void uefi_vars_policies_clear(uefi_vars_state *uv)
233 {
234 uefi_var_policy *pol;
235
236 while (!QTAILQ_EMPTY(&uv->var_policies)) {
237 pol = QTAILQ_FIRST(&uv->var_policies);
238 QTAILQ_REMOVE(&uv->var_policies, pol, next);
239 g_free(pol->entry);
240 g_free(pol);
241 }
242 }
243
uefi_vars_mm_policy_error(mm_header * mhdr,mm_check_policy * mchk,uint64_t status)244 static size_t uefi_vars_mm_policy_error(mm_header *mhdr,
245 mm_check_policy *mchk,
246 uint64_t status)
247 {
248 mchk->result = status;
249 return sizeof(*mchk);
250 }
251
uefi_vars_mm_check_policy_is_enabled(uefi_vars_state * uv,mm_header * mhdr,mm_check_policy * mchk,void * func)252 static uint32_t uefi_vars_mm_check_policy_is_enabled(uefi_vars_state *uv,
253 mm_header *mhdr,
254 mm_check_policy *mchk,
255 void *func)
256 {
257 mm_check_policy_is_enabled *mpar = func;
258 size_t length;
259
260 length = sizeof(*mchk) + sizeof(*mpar);
261 if (mhdr->length < length) {
262 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
263 }
264
265 mpar->state = TRUE;
266 mchk->result = EFI_SUCCESS;
267 return sizeof(*mchk);
268 }
269
uefi_vars_mm_check_policy_register(uefi_vars_state * uv,mm_header * mhdr,mm_check_policy * mchk,void * func)270 static uint32_t uefi_vars_mm_check_policy_register(uefi_vars_state *uv,
271 mm_header *mhdr,
272 mm_check_policy *mchk,
273 void *func)
274 {
275 variable_policy_entry *pe = func;
276 uefi_var_policy *pol;
277 uint64_t length;
278
279 if (uadd64_overflow(sizeof(*mchk), pe->size, &length)) {
280 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
281 }
282 if (mhdr->length < length) {
283 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
284 }
285 if (pe->size < sizeof(*pe)) {
286 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
287 }
288 if (pe->offset_to_name < sizeof(*pe)) {
289 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
290 }
291
292 if (pe->lock_policy_type == VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE &&
293 pe->offset_to_name < sizeof(*pe) + sizeof(variable_lock_on_var_state)) {
294 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
295 }
296
297 /* check space for minimum string length */
298 if (pe->size < (size_t)pe->offset_to_name) {
299 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
300 }
301
302 if (!uefi_str_is_valid((void *)pe + pe->offset_to_name,
303 pe->size - pe->offset_to_name,
304 false)) {
305 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_INVALID_PARAMETER);
306 }
307
308 pol = find_policy(uv, pe->namespace,
309 (void *)pe + pe->offset_to_name,
310 pe->size - pe->offset_to_name);
311 if (pol) {
312 return uefi_vars_mm_policy_error(mhdr, mchk, EFI_ALREADY_STARTED);
313 }
314
315 uefi_vars_add_policy(uv, pe);
316
317 mchk->result = EFI_SUCCESS;
318 return sizeof(*mchk);
319 }
320
uefi_vars_mm_check_policy_proto(uefi_vars_state * uv)321 uint32_t uefi_vars_mm_check_policy_proto(uefi_vars_state *uv)
322 {
323 static const char *fnames[] = {
324 "zero",
325 "disable",
326 "is-enabled",
327 "register",
328 "dump",
329 "lock",
330 };
331 const char *fname;
332 mm_header *mhdr = (mm_header *) uv->buffer;
333 mm_check_policy *mchk = (mm_check_policy *) (uv->buffer + sizeof(*mhdr));
334 void *func = (uv->buffer + sizeof(*mhdr) + sizeof(*mchk));
335
336 if (mhdr->length < sizeof(*mchk)) {
337 return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE;
338 }
339
340 fname = mchk->command < ARRAY_SIZE(fnames)
341 ? fnames[mchk->command]
342 : "unknown";
343 trace_uefi_vars_policy_cmd(fname);
344
345 switch (mchk->command) {
346 case VAR_CHECK_POLICY_COMMAND_DISABLE:
347 mchk->result = EFI_UNSUPPORTED;
348 break;
349 case VAR_CHECK_POLICY_COMMAND_IS_ENABLED:
350 uefi_vars_mm_check_policy_is_enabled(uv, mhdr, mchk, func);
351 break;
352 case VAR_CHECK_POLICY_COMMAND_REGISTER:
353 if (uv->policy_locked) {
354 mchk->result = EFI_WRITE_PROTECTED;
355 } else {
356 uefi_vars_mm_check_policy_register(uv, mhdr, mchk, func);
357 }
358 break;
359 case VAR_CHECK_POLICY_COMMAND_LOCK:
360 uv->policy_locked = true;
361 mchk->result = EFI_SUCCESS;
362 break;
363 default:
364 mchk->result = EFI_UNSUPPORTED;
365 break;
366 }
367
368 uefi_trace_status(__func__, mchk->result);
369 return UEFI_VARS_STS_SUCCESS;
370 }
371