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