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