1 /*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * uefi vars device - EfiSmmVariableProtocol implementation
5 */
6 #include "qemu/osdep.h"
7 #include "qemu/error-report.h"
8 #include "system/dma.h"
9 #include "migration/vmstate.h"
10
11 #include "hw/uefi/var-service.h"
12 #include "hw/uefi/var-service-api.h"
13 #include "hw/uefi/var-service-edk2.h"
14
15 #include "trace.h"
16
17 #define EFI_VARIABLE_ATTRIBUTE_SUPPORTED \
18 (EFI_VARIABLE_NON_VOLATILE | \
19 EFI_VARIABLE_BOOTSERVICE_ACCESS | \
20 EFI_VARIABLE_RUNTIME_ACCESS | \
21 EFI_VARIABLE_HARDWARE_ERROR_RECORD | \
22 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \
23 EFI_VARIABLE_APPEND_WRITE)
24
25
26 const VMStateDescription vmstate_uefi_time = {
27 .name = "uefi-time",
28 .fields = (VMStateField[]) {
29 VMSTATE_UINT16(year, efi_time),
30 VMSTATE_UINT8(month, efi_time),
31 VMSTATE_UINT8(day, efi_time),
32 VMSTATE_UINT8(hour, efi_time),
33 VMSTATE_UINT8(minute, efi_time),
34 VMSTATE_UINT8(second, efi_time),
35 VMSTATE_UINT32(nanosecond, efi_time),
36 VMSTATE_END_OF_LIST()
37 },
38 };
39
40 const VMStateDescription vmstate_uefi_variable = {
41 .name = "uefi-variable",
42 .fields = (VMStateField[]) {
43 VMSTATE_UINT8_ARRAY_V(guid.data, uefi_variable, sizeof(QemuUUID), 0),
44 VMSTATE_UINT32(name_size, uefi_variable),
45 VMSTATE_UINT32(data_size, uefi_variable),
46 VMSTATE_UINT32(attributes, uefi_variable),
47 VMSTATE_VBUFFER_ALLOC_UINT32(name, uefi_variable, 0, NULL, name_size),
48 VMSTATE_VBUFFER_ALLOC_UINT32(data, uefi_variable, 0, NULL, data_size),
49 VMSTATE_STRUCT(time, uefi_variable, 0, vmstate_uefi_time, efi_time),
50 VMSTATE_END_OF_LIST()
51 },
52 };
53
uefi_vars_find_variable(uefi_vars_state * uv,QemuUUID guid,const uint16_t * name,uint64_t name_size)54 uefi_variable *uefi_vars_find_variable(uefi_vars_state *uv, QemuUUID guid,
55 const uint16_t *name, uint64_t name_size)
56 {
57 uefi_variable *var;
58
59 QTAILQ_FOREACH(var, &uv->variables, next) {
60 if (!uefi_str_equal(var->name, var->name_size,
61 name, name_size)) {
62 continue;
63 }
64 if (!qemu_uuid_is_equal(&var->guid, &guid)) {
65 continue;
66 }
67 if (!var->data_size) {
68 /* in process of being created/updated */
69 continue;
70 }
71 return var;
72 }
73 return NULL;
74 }
75
add_variable(uefi_vars_state * uv,QemuUUID guid,const uint16_t * name,uint64_t name_size,uint32_t attributes)76 static uefi_variable *add_variable(uefi_vars_state *uv, QemuUUID guid,
77 const uint16_t *name, uint64_t name_size,
78 uint32_t attributes)
79 {
80 uefi_variable *var;
81
82 var = g_new0(uefi_variable, 1);
83 var->guid = guid;
84 var->name = g_malloc(name_size);
85 memcpy(var->name, name, name_size);
86 var->name_size = name_size;
87 var->attributes = attributes;
88
89 var->attributes &= ~EFI_VARIABLE_APPEND_WRITE;
90
91 QTAILQ_INSERT_TAIL(&uv->variables, var, next);
92 return var;
93 }
94
del_variable(uefi_vars_state * uv,uefi_variable * var)95 static void del_variable(uefi_vars_state *uv, uefi_variable *var)
96 {
97 if (!var) {
98 return;
99 }
100
101 QTAILQ_REMOVE(&uv->variables, var, next);
102 g_free(var->data);
103 g_free(var->name);
104 g_free(var->digest);
105 g_free(var);
106 }
107
variable_size(uefi_variable * var)108 static size_t variable_size(uefi_variable *var)
109 {
110 size_t size;
111
112 size = sizeof(*var);
113 size += var->name_size;
114 size += var->data_size;
115 size += var->digest_size;
116 return size;
117 }
118
uefi_vars_set_variable(uefi_vars_state * uv,QemuUUID guid,const uint16_t * name,uint64_t name_size,uint32_t attributes,void * data,uint64_t data_size)119 void uefi_vars_set_variable(uefi_vars_state *uv, QemuUUID guid,
120 const uint16_t *name, uint64_t name_size,
121 uint32_t attributes,
122 void *data, uint64_t data_size)
123 {
124 uefi_variable *old_var, *new_var;
125
126 uefi_trace_variable(__func__, guid, name, name_size);
127
128 old_var = uefi_vars_find_variable(uv, guid, name, name_size);
129 if (old_var) {
130 uv->used_storage -= variable_size(old_var);
131 del_variable(uv, old_var);
132 }
133
134 new_var = add_variable(uv, guid, name, name_size, attributes);
135 new_var->data = g_malloc(data_size);
136 new_var->data_size = data_size;
137 memcpy(new_var->data, data, data_size);
138 uv->used_storage += variable_size(new_var);
139 }
140
uefi_vars_clear_volatile(uefi_vars_state * uv)141 void uefi_vars_clear_volatile(uefi_vars_state *uv)
142 {
143 uefi_variable *var, *n;
144
145 QTAILQ_FOREACH_SAFE(var, &uv->variables, next, n) {
146 if (var->attributes & EFI_VARIABLE_NON_VOLATILE) {
147 continue;
148 }
149 uv->used_storage -= variable_size(var);
150 del_variable(uv, var);
151 }
152 }
153
uefi_vars_clear_all(uefi_vars_state * uv)154 void uefi_vars_clear_all(uefi_vars_state *uv)
155 {
156 uefi_variable *var, *n;
157
158 QTAILQ_FOREACH_SAFE(var, &uv->variables, next, n) {
159 del_variable(uv, var);
160 }
161 uv->used_storage = 0;
162 }
163
uefi_vars_update_storage(uefi_vars_state * uv)164 void uefi_vars_update_storage(uefi_vars_state *uv)
165 {
166 uefi_variable *var;
167
168 uv->used_storage = 0;
169 QTAILQ_FOREACH(var, &uv->variables, next) {
170 uv->used_storage += variable_size(var);
171 }
172 }
173
check_access(uefi_vars_state * uv,uefi_variable * var)174 static gboolean check_access(uefi_vars_state *uv, uefi_variable *var)
175 {
176 if (!uv->exit_boot_service) {
177 if (!(var->attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)) {
178 return false;
179 }
180 } else {
181 if (!(var->attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
182 return false;
183 }
184 }
185 return true;
186 }
187
check_update(uefi_vars_state * uv,uefi_variable * old_var,uefi_variable * new_var)188 static efi_status check_update(uefi_vars_state *uv, uefi_variable *old_var,
189 uefi_variable *new_var)
190 {
191 efi_status status;
192
193 if (old_var) {
194 if (!check_access(uv, old_var)) {
195 return EFI_ACCESS_DENIED;
196 }
197 }
198
199 if (new_var) {
200 if (new_var->attributes & ~EFI_VARIABLE_ATTRIBUTE_SUPPORTED) {
201 return EFI_UNSUPPORTED;
202 }
203 if (!check_access(uv, new_var)) {
204 return EFI_ACCESS_DENIED;
205 }
206 }
207
208 if (old_var && new_var) {
209 if (old_var->attributes != new_var->attributes) {
210 return EFI_INVALID_PARAMETER;
211 }
212 }
213
214 if (new_var) {
215 /* create + update */
216 status = uefi_vars_policy_check(uv, new_var, old_var == NULL);
217 } else {
218 /* delete */
219 g_assert(old_var);
220 status = uefi_vars_policy_check(uv, old_var, false);
221 }
222 if (status != EFI_SUCCESS) {
223 return status;
224 }
225
226 status = uefi_vars_check_secure_boot(uv, new_var ?: old_var);
227 if (status != EFI_SUCCESS) {
228 return status;
229 }
230
231 return EFI_SUCCESS;
232 }
233
append_write(uefi_variable * old_var,uefi_variable * new_var)234 static void append_write(uefi_variable *old_var,
235 uefi_variable *new_var)
236 {
237 uefi_vars_siglist siglist;
238 uint64_t size;
239 void *data;
240
241 uefi_vars_siglist_init(&siglist);
242 uefi_vars_siglist_parse(&siglist, old_var->data, old_var->data_size);
243 uefi_vars_siglist_parse(&siglist, new_var->data, new_var->data_size);
244
245 size = uefi_vars_siglist_blob_size(&siglist);
246 data = g_malloc(size);
247 uefi_vars_siglist_blob_generate(&siglist, data, size);
248
249 g_free(new_var->data);
250 new_var->data = data;
251 new_var->data_size = size;
252
253 uefi_vars_siglist_free(&siglist);
254 }
255
uefi_vars_mm_error(mm_header * mhdr,mm_variable * mvar,uint64_t status)256 static size_t uefi_vars_mm_error(mm_header *mhdr, mm_variable *mvar,
257 uint64_t status)
258 {
259 mvar->status = status;
260 return sizeof(*mvar);
261 }
262
uefi_vars_mm_get_variable(uefi_vars_state * uv,mm_header * mhdr,mm_variable * mvar,void * func)263 static size_t uefi_vars_mm_get_variable(uefi_vars_state *uv, mm_header *mhdr,
264 mm_variable *mvar, void *func)
265 {
266 mm_variable_access *va = func;
267 uint16_t *name;
268 void *data;
269 uefi_variable *var;
270 uint64_t length;
271
272 length = sizeof(*mvar) + sizeof(*va);
273 if (mhdr->length < length) {
274 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
275 }
276
277 if (va->name_size > uv->max_storage ||
278 va->data_size > uv->max_storage) {
279 return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES);
280 }
281
282 name = func + sizeof(*va);
283 if (uadd64_overflow(length, va->name_size, &length)) {
284 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
285 }
286 if (mhdr->length < length) {
287 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
288 }
289
290 if (!uefi_str_is_valid(name, va->name_size, true)) {
291 return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER);
292 }
293
294 uefi_trace_variable(__func__, va->guid, name, va->name_size);
295
296 var = uefi_vars_find_variable(uv, va->guid, name, va->name_size);
297 if (!var) {
298 return uefi_vars_mm_error(mhdr, mvar, EFI_NOT_FOUND);
299 }
300
301 /* check permissions etc. */
302 if (!check_access(uv, var)) {
303 return uefi_vars_mm_error(mhdr, mvar, EFI_ACCESS_DENIED);
304 }
305
306 data = func + sizeof(*va) + va->name_size;
307 if (uadd64_overflow(length, va->data_size, &length)) {
308 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
309 }
310 if (uv->buf_size < length) {
311 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
312 }
313
314 va->attributes = var->attributes;
315 if (va->data_size < var->data_size) {
316 va->data_size = var->data_size;
317 length -= va->data_size;
318 mvar->status = EFI_BUFFER_TOO_SMALL;
319 } else {
320 va->data_size = var->data_size;
321 memcpy(data, var->data, var->data_size);
322 mvar->status = EFI_SUCCESS;
323 }
324 return length;
325 }
326
327 static size_t
uefi_vars_mm_get_next_variable(uefi_vars_state * uv,mm_header * mhdr,mm_variable * mvar,void * func)328 uefi_vars_mm_get_next_variable(uefi_vars_state *uv, mm_header *mhdr,
329 mm_variable *mvar, void *func)
330 {
331 mm_next_variable *nv = func;
332 uefi_variable *var;
333 uint16_t *name;
334 uint64_t length;
335
336 length = sizeof(*mvar) + sizeof(*nv);
337 if (mhdr->length < length) {
338 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
339 }
340
341 if (nv->name_size > uv->max_storage) {
342 return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES);
343 }
344
345 name = func + sizeof(*nv);
346 if (uadd64_overflow(length, nv->name_size, &length)) {
347 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
348 }
349 if (mhdr->length < length) {
350 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
351 }
352
353 if (!uefi_str_is_valid(name, nv->name_size, true)) {
354 return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER);
355 }
356
357 if (uefi_strlen(name, nv->name_size) == 0) {
358 /* empty string -> first */
359 var = QTAILQ_FIRST(&uv->variables);
360 while (var && !check_access(uv, var)) {
361 var = QTAILQ_NEXT(var, next);
362 }
363 if (!var) {
364 return uefi_vars_mm_error(mhdr, mvar, EFI_NOT_FOUND);
365 }
366 } else {
367 var = uefi_vars_find_variable(uv, nv->guid, name, nv->name_size);
368 if (!var) {
369 return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER);
370 }
371 do {
372 var = QTAILQ_NEXT(var, next);
373 } while (var && !check_access(uv, var));
374 if (!var) {
375 return uefi_vars_mm_error(mhdr, mvar, EFI_NOT_FOUND);
376 }
377 }
378
379 length = sizeof(*mvar) + sizeof(*nv) + var->name_size;
380 if (uv->buf_size < length) {
381 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
382 }
383
384 nv->guid = var->guid;
385 nv->name_size = var->name_size;
386 memcpy(name, var->name, var->name_size);
387 mvar->status = EFI_SUCCESS;
388 return length;
389 }
390
uefi_vars_mm_digest_compare(uefi_variable * old_var,uefi_variable * new_var)391 static bool uefi_vars_mm_digest_compare(uefi_variable *old_var,
392 uefi_variable *new_var)
393 {
394 if (!old_var->digest ||
395 !new_var->digest ||
396 !old_var->digest_size ||
397 !new_var->digest_size) {
398 /* should not happen */
399 trace_uefi_vars_security_violation("inconsistent authvar digest state");
400 return false;
401 }
402 if (old_var->digest_size != new_var->digest_size) {
403 trace_uefi_vars_security_violation("authvar digest size mismatch");
404 return false;
405 }
406 if (memcmp(old_var->digest, new_var->digest,
407 old_var->digest_size) != 0) {
408 trace_uefi_vars_security_violation("authvar digest data mismatch");
409 return false;
410 }
411 return true;
412 }
413
uefi_vars_mm_set_variable(uefi_vars_state * uv,mm_header * mhdr,mm_variable * mvar,void * func)414 static size_t uefi_vars_mm_set_variable(uefi_vars_state *uv, mm_header *mhdr,
415 mm_variable *mvar, void *func)
416 {
417 mm_variable_access *va = func;
418 uint32_t attributes = 0;
419 uint16_t *name;
420 void *data;
421 uefi_variable *old_var, *new_var;
422 uint64_t length;
423 size_t new_storage;
424 efi_status status;
425
426 length = sizeof(*mvar) + sizeof(*va);
427 if (mhdr->length < length) {
428 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
429 }
430
431 if (va->name_size > uv->max_storage ||
432 va->data_size > uv->max_storage) {
433 return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES);
434 }
435
436 name = func + sizeof(*va);
437 if (uadd64_overflow(length, va->name_size, &length)) {
438 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
439 }
440 if (mhdr->length < length) {
441 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
442 }
443
444 data = func + sizeof(*va) + va->name_size;
445 if (uadd64_overflow(length, va->data_size, &length)) {
446 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
447 }
448 if (mhdr->length < length) {
449 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
450 }
451
452 g_assert(va->name_size < G_MAXUINT32);
453 g_assert(va->data_size < G_MAXUINT32);
454
455 if (!uefi_str_is_valid(name, va->name_size, true)) {
456 return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER);
457 }
458
459 uefi_trace_variable(__func__, va->guid, name, va->name_size);
460
461 old_var = uefi_vars_find_variable(uv, va->guid, name, va->name_size);
462 if (va->data_size) {
463 new_var = add_variable(uv, va->guid, name, va->name_size,
464 va->attributes);
465 if (va->attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
466 /* not implemented (deprecated in uefi spec) */
467 warn_report("%s: AUTHENTICATED_WRITE_ACCESS", __func__);
468 mvar->status = EFI_UNSUPPORTED;
469 goto rollback;
470 } else if (va->attributes &
471 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
472 status = uefi_vars_check_auth_2(uv, new_var, va, data);
473 if (status != EFI_SUCCESS) {
474 mvar->status = status;
475 goto rollback;
476 }
477 if (old_var && new_var) {
478 if (uefi_time_compare(&old_var->time, &new_var->time) > 0) {
479 trace_uefi_vars_security_violation("time check failed");
480 mvar->status = EFI_SECURITY_VIOLATION;
481 goto rollback;
482 }
483 if (old_var->digest_size || new_var->digest_size) {
484 if (!uefi_vars_mm_digest_compare(old_var, new_var)) {
485 mvar->status = EFI_SECURITY_VIOLATION;
486 goto rollback;
487 }
488 }
489 }
490 } else {
491 new_var->data = g_malloc(va->data_size);
492 memcpy(new_var->data, data, va->data_size);
493 new_var->data_size = va->data_size;
494 }
495 if (!new_var->data) {
496 /* we land here when deleting authenticated variables */
497 del_variable(uv, new_var);
498 new_var = NULL;
499 }
500 } else {
501 new_var = NULL;
502 }
503
504 if (!old_var && !new_var) {
505 /* delete non-existing variable -> nothing to do */
506 mvar->status = EFI_SUCCESS;
507 return sizeof(*mvar);
508 }
509
510 /* check permissions etc. */
511 status = check_update(uv, old_var, new_var);
512 if (status != EFI_SUCCESS) {
513 mvar->status = status;
514 goto rollback;
515 }
516
517 if (va->attributes & EFI_VARIABLE_APPEND_WRITE && old_var && new_var) {
518 /* merge signature databases */
519 if (!uefi_vars_is_sb_any(new_var)) {
520 mvar->status = EFI_UNSUPPORTED;
521 goto rollback;
522 }
523 append_write(old_var, new_var);
524 }
525
526 /* check storage space */
527 new_storage = uv->used_storage;
528 if (old_var) {
529 new_storage -= variable_size(old_var);
530 }
531 if (new_var) {
532 new_storage += variable_size(new_var);
533 }
534 if (new_storage > uv->max_storage) {
535 mvar->status = EFI_OUT_OF_RESOURCES;
536 goto rollback;
537 }
538
539 attributes = new_var
540 ? new_var->attributes
541 : old_var->attributes;
542
543 /* all good, commit */
544 del_variable(uv, old_var);
545 uv->used_storage = new_storage;
546
547 if (attributes & EFI_VARIABLE_NON_VOLATILE) {
548 uefi_vars_json_save(uv);
549 }
550
551 if (new_var && uefi_vars_is_sb_pk(new_var)) {
552 uefi_vars_auth_init(uv);
553 }
554
555 mvar->status = EFI_SUCCESS;
556 return sizeof(*mvar);
557
558 rollback:
559 del_variable(uv, new_var);
560 return sizeof(*mvar);
561 }
562
uefi_vars_mm_variable_info(uefi_vars_state * uv,mm_header * mhdr,mm_variable * mvar,void * func)563 static size_t uefi_vars_mm_variable_info(uefi_vars_state *uv, mm_header *mhdr,
564 mm_variable *mvar, void *func)
565 {
566 mm_variable_info *vi = func;
567 uint64_t length;
568
569 length = sizeof(*mvar) + sizeof(*vi);
570 if (uv->buf_size < length) {
571 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
572 }
573
574 vi->max_storage_size = uv->max_storage;
575 vi->free_storage_size = uv->max_storage - uv->used_storage;
576 vi->max_variable_size = uv->max_storage >> 2;
577 vi->attributes = 0;
578
579 mvar->status = EFI_SUCCESS;
580 return length;
581 }
582
583 static size_t
uefi_vars_mm_get_payload_size(uefi_vars_state * uv,mm_header * mhdr,mm_variable * mvar,void * func)584 uefi_vars_mm_get_payload_size(uefi_vars_state *uv, mm_header *mhdr,
585 mm_variable *mvar, void *func)
586 {
587 mm_get_payload_size *ps = func;
588 uint64_t length;
589
590 length = sizeof(*mvar) + sizeof(*ps);
591 if (uv->buf_size < length) {
592 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
593 }
594
595 ps->payload_size = uv->buf_size;
596 mvar->status = EFI_SUCCESS;
597 return length;
598 }
599
600 static size_t
uefi_vars_mm_lock_variable(uefi_vars_state * uv,mm_header * mhdr,mm_variable * mvar,void * func)601 uefi_vars_mm_lock_variable(uefi_vars_state *uv, mm_header *mhdr,
602 mm_variable *mvar, void *func)
603 {
604 mm_lock_variable *lv = func;
605 variable_policy_entry *pe;
606 uint16_t *name, *dest;
607 uint64_t length;
608
609 length = sizeof(*mvar) + sizeof(*lv);
610 if (mhdr->length < length) {
611 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
612 }
613
614 name = func + sizeof(*lv);
615 if (uadd64_overflow(length, lv->name_size, &length)) {
616 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
617 }
618 if (mhdr->length < length) {
619 return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
620 }
621
622 uefi_trace_variable(__func__, lv->guid, name, lv->name_size);
623
624 pe = g_malloc0(sizeof(*pe) + lv->name_size);
625 pe->version = VARIABLE_POLICY_ENTRY_REVISION;
626 pe->size = sizeof(*pe) + lv->name_size;
627 pe->offset_to_name = sizeof(*pe);
628 pe->namespace = lv->guid;
629 pe->min_size = 0;
630 pe->max_size = UINT32_MAX;
631 pe->attributes_must_have = 0;
632 pe->attributes_cant_have = 0;
633 pe->lock_policy_type = VARIABLE_POLICY_TYPE_LOCK_NOW;
634
635 dest = (void *)pe + pe->offset_to_name;
636 memcpy(dest, name, lv->name_size);
637
638 uefi_vars_add_policy(uv, pe);
639 g_free(pe);
640
641 mvar->status = EFI_SUCCESS;
642 return length;
643 }
644
uefi_vars_mm_vars_proto(uefi_vars_state * uv)645 uint32_t uefi_vars_mm_vars_proto(uefi_vars_state *uv)
646 {
647 static const char *fnames[] = {
648 "zero",
649 "get-variable",
650 "get-next-variable-name",
651 "set-variable",
652 "query-variable-info",
653 "ready-to-boot",
654 "exit-boot-service",
655 "get-statistics",
656 "lock-variable",
657 "var-check-prop-set",
658 "var-check-prop-get",
659 "get-payload-size",
660 "init-runtime-cache-contect",
661 "sync-runtime-cache",
662 "get-runtime-cache-info",
663 };
664 const char *fname;
665 uint64_t length;
666
667 mm_header *mhdr = (mm_header *) uv->buffer;
668 mm_variable *mvar = (mm_variable *) (uv->buffer + sizeof(*mhdr));
669 void *func = (uv->buffer + sizeof(*mhdr) + sizeof(*mvar));
670
671 if (mhdr->length < sizeof(*mvar)) {
672 return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE;
673 }
674
675 fname = mvar->function < ARRAY_SIZE(fnames)
676 ? fnames[mvar->function]
677 : "unknown";
678 trace_uefi_vars_proto_cmd(fname);
679
680 switch (mvar->function) {
681 case SMM_VARIABLE_FUNCTION_GET_VARIABLE:
682 length = uefi_vars_mm_get_variable(uv, mhdr, mvar, func);
683 break;
684
685 case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME:
686 length = uefi_vars_mm_get_next_variable(uv, mhdr, mvar, func);
687 break;
688
689 case SMM_VARIABLE_FUNCTION_SET_VARIABLE:
690 length = uefi_vars_mm_set_variable(uv, mhdr, mvar, func);
691 break;
692
693 case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO:
694 length = uefi_vars_mm_variable_info(uv, mhdr, mvar, func);
695 break;
696
697 case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE:
698 length = uefi_vars_mm_lock_variable(uv, mhdr, mvar, func);
699 break;
700
701 case SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE:
702 length = uefi_vars_mm_get_payload_size(uv, mhdr, mvar, func);
703 break;
704
705 case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:
706 trace_uefi_event("ready-to-boot");
707 uv->ready_to_boot = true;
708 mvar->status = EFI_SUCCESS;
709 length = 0;
710 break;
711
712 case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE:
713 trace_uefi_event("exit-boot-service");
714 uv->exit_boot_service = true;
715 mvar->status = EFI_SUCCESS;
716 length = 0;
717 break;
718
719 default:
720 length = uefi_vars_mm_error(mhdr, mvar, EFI_UNSUPPORTED);
721 break;
722 }
723
724 if (mhdr->length < length) {
725 mvar->status = EFI_BUFFER_TOO_SMALL;
726 }
727
728 uefi_trace_status(__func__, mvar->status);
729 return UEFI_VARS_STS_SUCCESS;
730 }
731