xref: /openbmc/qemu/hw/uefi/var-service-vars.c (revision 5836af0783213b9355a6bbf85d9e6bc4c9c9363f)
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