]> git.proxmox.com Git - efi-boot-shim.git/blame - mok.c
Fix format strings for 32-bit builds
[efi-boot-shim.git] / mok.c
CommitLineData
031e5cce 1// SPDX-License-Identifier: BSD-2-Clause-Patent
f892ac66 2/*
031e5cce 3 * mok.c - MoK variable processing
f892ac66 4 * Copyright 2017 Peter Jones <pjones@redhat.com>
f892ac66
MTL
5 */
6
7#include "shim.h"
8
9/*
10 * Check if a variable exists
11 */
12static BOOLEAN check_var(CHAR16 *varname)
13{
14 EFI_STATUS efi_status;
15 UINTN size = sizeof(UINT32);
16 UINT32 MokVar;
17 UINT32 attributes;
18
8529e0f7
SM
19 efi_status = RT->GetVariable(varname, &SHIM_LOCK_GUID, &attributes,
20 &size, (void *)&MokVar);
f892ac66
MTL
21 if (!EFI_ERROR(efi_status) || efi_status == EFI_BUFFER_TOO_SMALL)
22 return TRUE;
23
24 return FALSE;
25}
26
031e5cce
SM
27#define SetVariable(name, guid, attrs, varsz, var) \
28 ({ \
29 EFI_STATUS efi_status_; \
8529e0f7 30 efi_status_ = RT->SetVariable(name, guid, attrs, varsz, var); \
031e5cce
SM
31 dprint_(L"%a:%d:%a() SetVariable(\"%s\", ... varsz=0x%llx) = %r\n", \
32 __FILE__, __LINE__ - 5, __func__, name, varsz, \
33 efi_status_); \
34 efi_status_; \
35 })
36
f892ac66
MTL
37/*
38 * If the OS has set any of these variables we need to drop into MOK and
39 * handle them appropriately
40 */
41static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
42{
43 EFI_STATUS efi_status;
44
45 if (check_var(L"MokNew") || check_var(L"MokSB") ||
46 check_var(L"MokPW") || check_var(L"MokAuth") ||
47 check_var(L"MokDel") || check_var(L"MokDB") ||
48 check_var(L"MokXNew") || check_var(L"MokXDel") ||
8529e0f7 49 check_var(L"MokXAuth") || check_var(L"MokListTrustedNew")) {
f892ac66
MTL
50 efi_status = start_image(image_handle, MOK_MANAGER);
51
52 if (EFI_ERROR(efi_status)) {
53 perror(L"Failed to start MokManager: %r\n", efi_status);
54 return efi_status;
55 }
56 }
57
58 return EFI_SUCCESS;
59}
60
031e5cce
SM
61static vendor_addend_category_t
62categorize_authorized(struct mok_state_variable *v)
63{
64 if (!(v->addend && v->addend_size &&
65 *v->addend && *v->addend_size)) {
66 return VENDOR_ADDEND_NONE;
67 }
68
69 return vendor_authorized_category;
70}
71
72static vendor_addend_category_t
73categorize_deauthorized(struct mok_state_variable *v)
74{
75 if (!(v->addend && v->addend_size &&
76 *v->addend && *v->addend_size)) {
77 return VENDOR_ADDEND_NONE;
78 }
79
80 return VENDOR_ADDEND_DB;
81}
82
f892ac66
MTL
83#define MOK_MIRROR_KEYDB 0x01
84#define MOK_MIRROR_DELETE_FIRST 0x02
85#define MOK_VARIABLE_MEASURE 0x04
86#define MOK_VARIABLE_LOG 0x08
87
8529e0f7 88struct mok_state_variable mok_state_variable_data[] = {
f892ac66
MTL
89 {.name = L"MokList",
90 .name8 = "MokList",
91 .rtname = L"MokListRT",
031e5cce 92 .rtname8 = "MokListRT",
f892ac66
MTL
93 .guid = &SHIM_LOCK_GUID,
94 .yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
95 EFI_VARIABLE_NON_VOLATILE,
96 .no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
031e5cce
SM
97 .categorize_addend = categorize_authorized,
98 .addend = &vendor_authorized,
99 .addend_size = &vendor_authorized_size,
100#if defined(ENABLE_SHIM_CERT)
101 .build_cert = &build_cert,
102 .build_cert_size = &build_cert_size,
103#endif /* defined(ENABLE_SHIM_CERT) */
f892ac66 104 .flags = MOK_MIRROR_KEYDB |
031e5cce 105 MOK_MIRROR_DELETE_FIRST |
f892ac66
MTL
106 MOK_VARIABLE_LOG,
107 .pcr = 14,
108 },
109 {.name = L"MokListX",
110 .name8 = "MokListX",
111 .rtname = L"MokListXRT",
031e5cce 112 .rtname8 = "MokListXRT",
f892ac66
MTL
113 .guid = &SHIM_LOCK_GUID,
114 .yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
115 EFI_VARIABLE_NON_VOLATILE,
116 .no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
031e5cce
SM
117 .categorize_addend = categorize_deauthorized,
118 .addend = &vendor_deauthorized,
119 .addend_size = &vendor_deauthorized_size,
f892ac66 120 .flags = MOK_MIRROR_KEYDB |
031e5cce 121 MOK_MIRROR_DELETE_FIRST |
f892ac66
MTL
122 MOK_VARIABLE_LOG,
123 .pcr = 14,
124 },
125 {.name = L"MokSBState",
126 .name8 = "MokSBState",
127 .rtname = L"MokSBStateRT",
031e5cce 128 .rtname8 = "MokSBStateRT",
f892ac66
MTL
129 .guid = &SHIM_LOCK_GUID,
130 .yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
131 EFI_VARIABLE_NON_VOLATILE,
132 .no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
133 .flags = MOK_MIRROR_DELETE_FIRST |
134 MOK_VARIABLE_MEASURE |
135 MOK_VARIABLE_LOG,
136 .pcr = 14,
137 .state = &user_insecure_mode,
138 },
139 {.name = L"MokDBState",
140 .name8 = "MokDBState",
141 .rtname = L"MokIgnoreDB",
031e5cce 142 .rtname8 = "MokIgnoreDB",
f892ac66
MTL
143 .guid = &SHIM_LOCK_GUID,
144 .yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
145 EFI_VARIABLE_NON_VOLATILE,
146 .no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
147 .state = &ignore_db,
148 },
031e5cce
SM
149 {.name = SBAT_VAR_NAME,
150 .name8 = SBAT_VAR_NAME8,
151 .rtname = SBAT_RT_VAR_NAME,
152 .rtname8 = SBAT_RT_VAR_NAME8,
153 .guid = &SHIM_LOCK_GUID,
154 .yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
155 EFI_VARIABLE_NON_VOLATILE,
156 /*
157 * we're enforcing that SBAT can't have an RT flag here because
158 * there's no way to tell whether it's an authenticated variable.
159 */
160#if !defined(ENABLE_SHIM_DEVEL)
161 .no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
162#else
163 .no_attr = 0,
164#endif
165 .flags = MOK_MIRROR_DELETE_FIRST |
166 MOK_VARIABLE_MEASURE,
167 .pcr = 7,
168 },
8529e0f7
SM
169 {.name = L"MokListTrusted",
170 .name8 = "MokListTrusted",
171 .rtname = L"MokListTrustedRT",
172 .rtname8 = "MokListTrustedRT",
173 .guid = &SHIM_LOCK_GUID,
174 .yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
175 EFI_VARIABLE_NON_VOLATILE,
176 .no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
177 .flags = MOK_MIRROR_DELETE_FIRST |
178 MOK_VARIABLE_MEASURE |
179 MOK_VARIABLE_LOG,
180 .pcr = 14,
181 .state = &trust_mok_list,
182 },
f892ac66
MTL
183 { NULL, }
184};
8529e0f7
SM
185size_t n_mok_state_variables = sizeof(mok_state_variable_data) / sizeof(mok_state_variable_data[0]);
186struct mok_state_variable *mok_state_variables = &mok_state_variable_data[0];
f892ac66 187
031e5cce
SM
188#define should_mirror_addend(v) (((v)->categorize_addend) && ((v)->categorize_addend(v) != VENDOR_ADDEND_NONE))
189
190static inline BOOLEAN NONNULL(1)
191should_mirror_build_cert(struct mok_state_variable *v)
192{
193 return (v->build_cert && v->build_cert_size &&
194 *v->build_cert && *v->build_cert_size) ? TRUE : FALSE;
195}
196
197static const uint8_t null_sha256[32] = { 0, };
198
199typedef UINTN SIZE_T;
200
8529e0f7
SM
201#define EFI_MAJOR_VERSION(tablep) ((UINT16)((((tablep)->Hdr.Revision) >> 16) & 0xfffful))
202#define EFI_MINOR_VERSION(tablep) ((UINT16)(((tablep)->Hdr.Revision) & 0xfffful))
203
031e5cce
SM
204static EFI_STATUS
205get_max_var_sz(UINT32 attrs, SIZE_T *max_var_szp)
206{
207 EFI_STATUS efi_status;
208 uint64_t max_storage_sz = 0;
209 uint64_t remaining_sz = 0;
210 uint64_t max_var_sz = 0;
211
212 *max_var_szp = 0;
8529e0f7
SM
213 if (EFI_MAJOR_VERSION(RT) < 2) {
214 dprint(L"EFI %d.%d; no RT->QueryVariableInfo(). Using 1024!\n",
215 EFI_MAJOR_VERSION(RT), EFI_MINOR_VERSION(RT));
216 max_var_sz = remaining_sz = max_storage_sz = 1024;
217 efi_status = EFI_SUCCESS;
218 } else {
219 dprint(L"calling RT->QueryVariableInfo() at 0x%lx\n",
220 RT->QueryVariableInfo);
221 efi_status = RT->QueryVariableInfo(attrs, &max_storage_sz,
222 &remaining_sz, &max_var_sz);
223 if (EFI_ERROR(efi_status)) {
224 perror(L"Could not get variable storage info: %r\n",
225 efi_status);
226 return efi_status;
227 }
031e5cce
SM
228 }
229
230 /*
231 * I just don't trust implementations to not be showing static data
232 * for max_var_sz
233 */
234 *max_var_szp = (max_var_sz < remaining_sz) ? max_var_sz : remaining_sz;
235 dprint("max_var_sz:%lx remaining_sz:%lx max_storage_sz:%lx\n",
236 max_var_sz, remaining_sz, max_storage_sz);
237 return efi_status;
238}
239
240/*
241 * If any entries fit in < maxsz, and nothing goes wrong, create a variable
242 * of the given name and guid with as many esd entries as possible in it,
243 * and updates *esdp with what would be the next entry (even if makes *esdp
244 * > esl+esl->SignatureListSize), and returns whatever SetVariable()
245 * returns
246 *
247 * If no entries fit (i.e. sizeof(esl) + esl->SignatureSize > maxsz),
248 * returns EFI_BUFFER_TOO_SMALL;
249 */
250static EFI_STATUS
251mirror_one_esl(CHAR16 *name, EFI_GUID *guid, UINT32 attrs,
252 EFI_SIGNATURE_LIST *esl, EFI_SIGNATURE_DATA *esd,
253 SIZE_T howmany)
254{
255 EFI_STATUS efi_status;
256 SIZE_T varsz = 0;
257 UINT8 *var;
258
259 /*
260 * We always assume esl->SignatureHeaderSize is 0 (and so far,
261 * that's true as per UEFI 2.8)
262 */
263 dprint(L"Trying to add %lx signatures to \"%s\" of size %lx\n",
264 howmany, name, esl->SignatureSize);
265
266 /*
267 * Because of the semantics of variable_create_esl(), the first
268 * owner guid from the data is not part of esdsz, or the data.
269 *
270 * Compensate here.
271 */
272 efi_status = variable_create_esl(esd, howmany,
273 &esl->SignatureType,
274 esl->SignatureSize,
275 &var, &varsz);
276 if (EFI_ERROR(efi_status) || !var || !varsz) {
277 LogError(L"Couldn't allocate %lu bytes for mok variable \"%s\": %r\n",
278 varsz, var, efi_status);
279 return efi_status;
280 }
281
282 dprint(L"new esl:\n");
283 dhexdumpat(var, varsz, 0);
284
285 efi_status = SetVariable(name, guid, attrs, varsz, var);
286 FreePool(var);
287 if (EFI_ERROR(efi_status)) {
288 LogError(L"Couldn't create mok variable \"%s\": %r\n",
289 varsz, var, efi_status);
290 return efi_status;
291 }
292
293 return efi_status;
294}
295
296static EFI_STATUS
297mirror_mok_db(CHAR16 *name, CHAR8 *name8, EFI_GUID *guid, UINT32 attrs,
298 UINT8 *FullData, SIZE_T FullDataSize, BOOLEAN only_first)
f892ac66
MTL
299{
300 EFI_STATUS efi_status = EFI_SUCCESS;
031e5cce
SM
301 SIZE_T max_var_sz;
302
303 efi_status = get_max_var_sz(attrs, &max_var_sz);
8529e0f7 304 if (EFI_ERROR(efi_status) && efi_status != EFI_UNSUPPORTED) {
031e5cce
SM
305 LogError(L"Could not get maximum variable size: %r",
306 efi_status);
307 return efi_status;
308 }
309
8529e0f7
SM
310 /* Some UEFI environment such as u-boot doesn't implement
311 * QueryVariableInfo() and we will only get EFI_UNSUPPORTED when
312 * querying the available space. In this case, we just mirror
313 * the variable directly. */
314 if (FullDataSize <= max_var_sz || efi_status == EFI_UNSUPPORTED) {
315 efi_status = EFI_SUCCESS;
031e5cce
SM
316 if (only_first)
317 efi_status = SetVariable(name, guid, attrs,
318 FullDataSize, FullData);
f892ac66 319
031e5cce
SM
320 return efi_status;
321 }
322
323 CHAR16 *namen;
324 CHAR8 *namen8;
325 UINTN namelen, namesz;
326
327 namelen = StrLen(name);
328 namesz = namelen * 2;
329 if (only_first) {
330 namen = name;
331 namen8 = name8;
332 } else {
333 namelen += 18;
334 namesz += 34;
335 namen = AllocateZeroPool(namesz);
336 if (!namen) {
337 LogError(L"Could not allocate %lu bytes", namesz);
338 return EFI_OUT_OF_RESOURCES;
339 }
340 namen8 = AllocateZeroPool(namelen);
341 if (!namen8) {
342 FreePool(namen);
343 LogError(L"Could not allocate %lu bytes", namelen);
f892ac66
MTL
344 return EFI_OUT_OF_RESOURCES;
345 }
031e5cce
SM
346 }
347
348 UINTN pos, i;
349 const SIZE_T minsz = sizeof(EFI_SIGNATURE_LIST)
350 + sizeof(EFI_SIGNATURE_DATA)
351 + SHA1_DIGEST_SIZE;
352 BOOLEAN did_one = FALSE;
353
354 /*
355 * Create any entries that can fit.
356 */
357 if (!only_first) {
358 dprint(L"full data for \"%s\":\n", name);
359 dhexdumpat(FullData, FullDataSize, 0);
360 }
361 EFI_SIGNATURE_LIST *esl = NULL;
362 UINTN esl_end_pos = 0;
363 for (i = 0, pos = 0; FullDataSize - pos >= minsz && FullData; ) {
364 EFI_SIGNATURE_DATA *esd = NULL;
365
366 dprint(L"pos:0x%llx FullDataSize:0x%llx\n", pos, FullDataSize);
367 if (esl == NULL || pos >= esl_end_pos) {
368 UINT8 *nesl = FullData + pos;
369 dprint(L"esl:0x%llx->0x%llx\n", esl, nesl);
370 esl = (EFI_SIGNATURE_LIST *)nesl;
371 esl_end_pos = pos + esl->SignatureListSize;
372 dprint(L"pos:0x%llx->0x%llx\n", pos, pos + sizeof(*esl));
373 pos += sizeof(*esl);
374 }
375 esd = (EFI_SIGNATURE_DATA *)(FullData + pos);
376 if (pos >= FullDataSize)
377 break;
378 if (esl->SignatureListSize == 0 || esl->SignatureSize == 0)
379 break;
380
381 dprint(L"esl[%lu] 0x%llx = {sls=0x%lx, ss=0x%lx} esd:0x%llx\n",
382 i, esl, esl->SignatureListSize, esl->SignatureSize, esd);
383
384 if (!only_first) {
385 SPrint(namen, namelen, L"%s%lu", name, i);
386 namen[namelen-1] = 0;
387 /* uggggh */
388 UINTN j;
389 for (j = 0; j < namelen; j++)
390 namen8[j] = (CHAR8)(namen[j] & 0xff);
391 namen8[namelen - 1] = 0;
392 }
393
394 /*
395 * In case max_var_sz is computed dynamically, refresh the
396 * value here.
397 */
398 efi_status = get_max_var_sz(attrs, &max_var_sz);
399 if (EFI_ERROR(efi_status)) {
400 LogError(L"Could not get maximum variable size: %r",
401 efi_status);
402 if (!only_first) {
403 FreePool(namen);
404 FreePool(namen8);
405 }
406 return efi_status;
407 }
408
409 /* The name counts towards the size of the variable */
410 max_var_sz -= (StrLen(namen) + 1) * 2;
411 dprint(L"max_var_sz - name: %lx\n", max_var_sz);
412
413 SIZE_T howmany;
414 howmany = MIN((max_var_sz - sizeof(*esl)) / esl->SignatureSize,
415 (esl_end_pos - pos) / esl->SignatureSize);
416 if (howmany == 0) {
417 /* No signatures from this ESL can be mirrored in to a
418 * single variable, so skip it.
419 */
420 dprint(L"skipping esl, pos:0x%llx->0x%llx\n", pos, esl_end_pos);
421 pos = esl_end_pos;
422 continue;
423 }
424
425 UINTN adj = howmany * esl->SignatureSize;
426
427 if (!only_first && i == 0) {
428 dprint(L"pos:0x%llx->0x%llx\n", pos, pos + adj);
429 pos += adj;
430 i++;
431 continue;
432
433 }
434
435 efi_status = mirror_one_esl(namen, guid, attrs,
436 esl, esd, howmany);
437 dprint(L"esd:0x%llx adj:0x%llx\n", esd, adj);
438 if (EFI_ERROR(efi_status)) {
439 LogError(L"Could not mirror mok variable \"%s\": %r\n",
440 namen, efi_status);
441 break;
442 }
443
444 dprint(L"pos:0x%llx->0x%llx\n", pos, pos + adj);
445 pos += adj;
446 did_one = TRUE;
447 if (only_first)
448 break;
449 i++;
450 }
451
452 if (EFI_ERROR(efi_status)) {
453 perror(L"Failed to set %s: %r\n", name, efi_status);
454 } else if (only_first && !did_one) {
455 /*
456 * In this case we're going to try to create a
457 * dummy variable so that there's one there. It
458 * may or may not work, because on some firmware
459 * builds when the SetVariable call above fails it
460 * does actually set the variable(!), so aside from
461 * not using the allocation if it doesn't work, we
462 * don't care about failures here.
463 */
464 UINT8 *var;
465 UINTN varsz;
f892ac66 466
031e5cce
SM
467 efi_status = variable_create_esl_with_one_signature(
468 null_sha256, sizeof(null_sha256),
469 &EFI_CERT_SHA256_GUID, &SHIM_LOCK_GUID,
470 &var, &varsz);
471 /*
472 * from here we don't really care if it works or
473 * doesn't.
474 */
475 if (!EFI_ERROR(efi_status) && var && varsz) {
476 efi_status = SetVariable(name, guid,
477 EFI_VARIABLE_BOOTSERVICE_ACCESS
478 | EFI_VARIABLE_RUNTIME_ACCESS,
479 varsz, var);
480 FreePool(var);
481 }
482 }
483 return efi_status;
484}
485
486
487static EFI_STATUS NONNULL(1)
488mirror_one_mok_variable(struct mok_state_variable *v,
489 BOOLEAN only_first)
490{
491 EFI_STATUS efi_status = EFI_SUCCESS;
492 uint8_t *FullData = NULL;
493 size_t FullDataSize = 0;
494 vendor_addend_category_t addend_category = VENDOR_ADDEND_NONE;
495 uint8_t *p = NULL;
496 uint32_t attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
497 EFI_VARIABLE_RUNTIME_ACCESS;
498 BOOLEAN measure = v->flags & MOK_VARIABLE_MEASURE;
499 BOOLEAN log = v->flags & MOK_VARIABLE_LOG;
500 size_t build_cert_esl_sz = 0, addend_esl_sz = 0;
501 bool reuse = FALSE;
502
503 if (v->categorize_addend)
504 addend_category = v->categorize_addend(v);
505
506 /*
507 * if it is, there's more data
508 */
509 if (v->flags & MOK_MIRROR_KEYDB) {
510
511 /*
512 * We're mirroring (into) an efi security database, aka an
513 * array of EFI_SIGNATURE_LIST. Its layout goes like:
514 *
515 * existing_variable_data
516 * existing_variable_data_size
517 * if flags & MOK_MIRROR_KEYDB
518 * if build_cert
519 * build_cert_esl
520 * build_cert_header (always sz=0)
521 * build_cert_esd[0] { owner, data }
522 * if addend==vendor_db
523 * for n=[1..N]
524 * vendor_db_esl_n
525 * vendor_db_header_n (always sz=0)
526 * vendor_db_esd_n[m] {{ owner, data }, ... }
527 * elif addend==vendor_cert
528 * vendor_cert_esl
529 * vendor_cert_header (always sz=0)
530 * vendor_cert_esd[1] { owner, data }
531 *
532 * first we determine the size of the variable, then alloc
533 * and add the data.
534 */
535
536 /*
537 * *first* vendor_db or vendor_cert
538 */
539 switch (addend_category) {
540 case VENDOR_ADDEND_DB:
541 /*
542 * if it's an ESL already, we use it wholesale
543 */
544 FullDataSize += *v->addend_size;
545 dprint(L"FullDataSize:%lu FullData:0x%llx\n",
546 FullDataSize, FullData);
547 break;
548 case VENDOR_ADDEND_X509:
549 efi_status = fill_esl_with_one_signature(*v->addend,
550 *v->addend_size,
551 &EFI_CERT_TYPE_X509_GUID,
552 &SHIM_LOCK_GUID,
553 NULL,
554 &addend_esl_sz);
555 if (efi_status != EFI_BUFFER_TOO_SMALL) {
556 perror(L"Could not add built-in cert to %s: %r\n",
557 v->name, efi_status);
558 return efi_status;
559 }
560 FullDataSize += addend_esl_sz;
561 dprint(L"FullDataSize:%lu FullData:0x%llx\n",
562 FullDataSize, FullData);
563 break;
564 default:
565 case VENDOR_ADDEND_NONE:
566 dprint(L"FullDataSize:%lu FullData:0x%llx\n",
567 FullDataSize, FullData);
568 break;
569 }
570
571 /*
572 * then the build cert if it's there
573 */
574 if (should_mirror_build_cert(v)) {
575 efi_status = fill_esl_with_one_signature(*v->build_cert,
576 *v->build_cert_size,
577 &EFI_CERT_TYPE_X509_GUID,
578 &SHIM_LOCK_GUID,
579 NULL, &build_cert_esl_sz);
580 if (efi_status != EFI_BUFFER_TOO_SMALL) {
581 perror(L"Could not add built-in cert to %s: %r\n",
582 v->name, efi_status);
583 return efi_status;
584 }
585 FullDataSize += build_cert_esl_sz;
586 dprint(L"FullDataSize:0x%lx FullData:0x%llx\n",
587 FullDataSize, FullData);
588 }
589
590 }
591
592 /*
593 * we're always mirroring the original data, whether this is an efi
594 * security database or not
595 */
596 dprint(L"v->name:\"%s\" v->rtname:\"%s\"\n", v->name, v->rtname);
597 dprint(L"v->data_size:%lu v->data:0x%llx\n", v->data_size, v->data);
598 dprint(L"FullDataSize:%lu FullData:0x%llx\n", FullDataSize, FullData);
599 if (v->data_size) {
600 FullDataSize += v->data_size;
601 dprint(L"FullDataSize:%lu FullData:0x%llx\n",
602 FullDataSize, FullData);
603 }
604 if (v->data_size == FullDataSize)
605 reuse = TRUE;
606
607 /*
608 * Now we have the full size
609 */
610 if (FullDataSize) {
611 /*
612 * allocate the buffer, or use the old one if it's just the
613 * existing data.
614 */
615 if (FullDataSize == v->data_size) {
616 FullData = v->data;
617 FullDataSize = v->data_size;
618 p = FullData + FullDataSize;
619 dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
620 FullDataSize, FullData, p, p-(uintptr_t)FullData);
621 v->data = NULL;
622 v->data_size = 0;
623 } else {
624 dprint(L"FullDataSize:%lu FullData:0x%llx allocating FullData\n",
625 FullDataSize, FullData);
626 /*
627 * make sure we've got some zeroes at the end, just
628 * in case.
629 */
630 UINTN new, allocsz;
631
632 allocsz = FullDataSize + sizeof(EFI_SIGNATURE_LIST);
633 new = ALIGN_VALUE(allocsz, 4096);
634 allocsz = new == allocsz ? new + 4096 : new;
635 FullData = AllocateZeroPool(allocsz);
636 if (!FullData) {
637 perror(L"Failed to allocate %lu bytes for %s\n",
638 FullDataSize, v->name);
639 return EFI_OUT_OF_RESOURCES;
640 }
641 p = FullData;
642 }
643 }
644 dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
645 FullDataSize, FullData, p, p-(uintptr_t)FullData);
646
647 /*
648 * Now fill it.
649 */
650 if (v->flags & MOK_MIRROR_KEYDB) {
651 /*
652 * first vendor_cert or vendor_db
653 */
654 switch (addend_category) {
655 case VENDOR_ADDEND_DB:
656 CopyMem(p, *v->addend, *v->addend_size);
657 p += *v->addend_size;
658 dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
659 FullDataSize, FullData, p, p-(uintptr_t)FullData);
660 break;
661 case VENDOR_ADDEND_X509:
662 efi_status = fill_esl_with_one_signature(*v->addend,
663 *v->addend_size,
664 &EFI_CERT_TYPE_X509_GUID,
665 &SHIM_LOCK_GUID,
666 p, &addend_esl_sz);
667 if (EFI_ERROR(efi_status)) {
668 perror(L"Could not add built-in cert to %s: %r\n",
669 v->name, efi_status);
670 return efi_status;
671 }
672 p += addend_esl_sz;
673 dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
674 FullDataSize, FullData, p, p-(uintptr_t)FullData);
675 break;
676 default:
677 case VENDOR_ADDEND_NONE:
678 dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
679 FullDataSize, FullData, p, p-(uintptr_t)FullData);
680 break;
681 }
682
683 /*
684 * then is the build cert
685 */
686 dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
687 FullDataSize, FullData, p, p-(uintptr_t)FullData);
688 if (should_mirror_build_cert(v)) {
689 efi_status = fill_esl_with_one_signature(*v->build_cert,
690 *v->build_cert_size,
691 &EFI_CERT_TYPE_X509_GUID,
692 &SHIM_LOCK_GUID,
693 p, &build_cert_esl_sz);
694 if (EFI_ERROR(efi_status)) {
695 perror(L"Could not add built-in cert to %s: %r\n",
696 v->name, efi_status);
697 return efi_status;
698 }
699 p += build_cert_esl_sz;
700 dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
701 FullDataSize, FullData, p, p-(uintptr_t)FullData);
702 }
703 }
704
705 /*
706 * last bit is existing data, unless it's the only thing,
707 * in which case it's already there.
708 */
709 if (!reuse) {
710 dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
711 FullDataSize, FullData, p, p-(uintptr_t)FullData);
712 if (v->data && v->data_size) {
f892ac66
MTL
713 CopyMem(p, v->data, v->data_size);
714 p += v->data_size;
715 }
031e5cce
SM
716 dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
717 FullDataSize, FullData, p, p-(uintptr_t)FullData);
f892ac66
MTL
718 }
719
031e5cce
SM
720 /*
721 * We always want to create our key databases, so in this case we
722 * need a dummy entry
723 */
724 if ((v->flags & MOK_MIRROR_KEYDB) && FullDataSize == 0) {
725 efi_status = variable_create_esl_with_one_signature(
726 null_sha256, sizeof(null_sha256),
727 &EFI_CERT_SHA256_GUID, &SHIM_LOCK_GUID,
728 &FullData, &FullDataSize);
f892ac66 729 if (EFI_ERROR(efi_status)) {
031e5cce
SM
730 perror(L"Failed to allocate %lu bytes for %s\n",
731 FullDataSize, v->name);
732 return efi_status;
f892ac66 733 }
031e5cce
SM
734 p = FullData + FullDataSize;
735 dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
736 FullDataSize, FullData, p, p-(uintptr_t)FullData);
737 }
738
739 dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
740 FullDataSize, FullData, p, p-(uintptr_t)FullData);
741 if (FullDataSize && v->flags & MOK_MIRROR_KEYDB) {
742 dprint(L"calling mirror_mok_db(\"%s\", datasz=%lu)\n",
743 v->rtname, FullDataSize);
744 efi_status = mirror_mok_db(v->rtname, (CHAR8 *)v->rtname8, v->guid,
745 attrs, FullData, FullDataSize,
746 only_first);
747 dprint(L"mirror_mok_db(\"%s\", datasz=%lu) returned %r\n",
748 v->rtname, FullDataSize, efi_status);
749 } else if (FullDataSize && only_first) {
750 efi_status = SetVariable(v->rtname, v->guid, attrs,
751 FullDataSize, FullData);
f892ac66 752 }
031e5cce
SM
753 if (FullDataSize && only_first) {
754 if (measure) {
755 /*
756 * Measure this into PCR 7 in the Microsoft format
757 */
758 efi_status = tpm_measure_variable(v->name, *v->guid,
759 FullDataSize, FullData);
760 if (EFI_ERROR(efi_status)) {
761 dprint(L"tpm_measure_variable(\"%s\",%lu,0x%llx)->%r\n",
762 v->name, FullDataSize, FullData, efi_status);
763 return efi_status;
764 }
765 }
f892ac66 766
031e5cce
SM
767 if (log) {
768 /*
769 * Log this variable into whichever PCR the table
770 * says.
771 */
772 EFI_PHYSICAL_ADDRESS datap =
773 (EFI_PHYSICAL_ADDRESS)(UINTN)FullData,
774 efi_status = tpm_log_event(datap, FullDataSize,
775 v->pcr, (CHAR8 *)v->name8);
776 if (EFI_ERROR(efi_status)) {
777 dprint(L"tpm_log_event(0x%llx, %lu, %lu, \"%s\")->%r\n",
778 FullData, FullDataSize, v->pcr, v->name,
779 efi_status);
780 return efi_status;
781 }
782 }
783
784 }
785 if (v->data && v->data_size && v->data != FullData) {
786 FreePool(v->data);
787 v->data = NULL;
788 v->data_size = 0;
789 }
790 v->data = FullData;
791 v->data_size = FullDataSize;
792 dprint(L"returning %r\n", efi_status);
f892ac66
MTL
793 return efi_status;
794}
795
031e5cce
SM
796/*
797 * Mirror a variable if it has an rtname, and preserve any
798 * EFI_SECURITY_VIOLATION status at the same time.
799 */
800static EFI_STATUS NONNULL(1)
801maybe_mirror_one_mok_variable(struct mok_state_variable *v,
802 EFI_STATUS ret, BOOLEAN only_first)
803{
804 EFI_STATUS efi_status;
805 BOOLEAN present = FALSE;
806
807 if (v->rtname) {
8529e0f7 808 if (only_first && (v->flags & MOK_MIRROR_DELETE_FIRST)) {
031e5cce
SM
809 dprint(L"deleting \"%s\"\n", v->rtname);
810 efi_status = LibDeleteVariable(v->rtname, v->guid);
811 dprint(L"LibDeleteVariable(\"%s\",...) => %r\n", v->rtname, efi_status);
812 }
813
814 efi_status = mirror_one_mok_variable(v, only_first);
815 if (EFI_ERROR(efi_status)) {
816 if (ret != EFI_SECURITY_VIOLATION)
817 ret = efi_status;
818 perror(L"Could not create %s: %r\n", v->rtname,
819 efi_status);
820 }
821 }
822
823 present = (v->data && v->data_size) ? TRUE : FALSE;
824 if (!present)
825 return ret;
826
827 if (v->data_size == sizeof(UINT8) && v->state) {
828 *v->state = v->data[0];
829 }
830
831 return ret;
832}
833
031e5cce
SM
834EFI_STATUS import_one_mok_state(struct mok_state_variable *v,
835 BOOLEAN only_first)
836{
837 EFI_STATUS ret = EFI_SUCCESS;
838 EFI_STATUS efi_status;
839
031e5cce
SM
840 UINT32 attrs = 0;
841 BOOLEAN delete = FALSE;
842
843 dprint(L"importing mok state for \"%s\"\n", v->name);
844
8529e0f7
SM
845 if (!v->data && !v->data_size) {
846 efi_status = get_variable_attr(v->name,
847 &v->data, &v->data_size,
848 *v->guid, &attrs);
849 if (efi_status == EFI_NOT_FOUND) {
850 v->data = NULL;
851 v->data_size = 0;
852 } else if (EFI_ERROR(efi_status)) {
853 perror(L"Could not verify %s: %r\n", v->name,
854 efi_status);
031e5cce 855 delete = TRUE;
8529e0f7
SM
856 } else {
857 if (!(attrs & v->yes_attr)) {
858 perror(L"Variable %s is missing attributes:\n",
859 v->name);
860 perror(L" 0x%08x should have 0x%08x set.\n",
861 attrs, v->yes_attr);
862 delete = TRUE;
863 }
864 if (attrs & v->no_attr) {
865 perror(L"Variable %s has incorrect attribute:\n",
866 v->name);
867 perror(L" 0x%08x should not have 0x%08x set.\n",
868 attrs, v->no_attr);
869 delete = TRUE;
870 }
031e5cce
SM
871 }
872 }
873 if (delete == TRUE) {
874 perror(L"Deleting bad variable %s\n", v->name);
875 efi_status = LibDeleteVariable(v->name, v->guid);
876 if (EFI_ERROR(efi_status)) {
877 perror(L"Failed to erase %s\n", v->name);
878 ret = EFI_SECURITY_VIOLATION;
879 }
880 FreePool(v->data);
881 v->data = NULL;
882 v->data_size = 0;
883 }
884
885 dprint(L"maybe mirroring \"%s\". original data:\n", v->name);
8529e0f7
SM
886 if (v->data && v->data_size) {
887 dhexdumpat(v->data, v->data_size, 0);
888 }
031e5cce
SM
889
890 ret = maybe_mirror_one_mok_variable(v, ret, only_first);
891 dprint(L"returning %r\n", ret);
892 return ret;
893}
894
f892ac66
MTL
895/*
896 * Verify our non-volatile MoK state. This checks the variables above
897 * accessable and have valid attributes. If they don't, it removes
898 * them. If any of them can't be removed, our ability to do this is
899 * comprimized, so return EFI_SECURITY_VIOLATION.
900 *
901 * Any variable that isn't deleted and has ->measure == TRUE is then
902 * measured into the tpm.
903 *
904 * Any variable with a ->rtname element is then mirrored to a
905 * runtime-accessable version. The new ones won't be marked NV, so the OS
906 * can't modify them.
907 */
908EFI_STATUS import_mok_state(EFI_HANDLE image_handle)
909{
910 UINTN i;
911 EFI_STATUS ret = EFI_SUCCESS;
912 EFI_STATUS efi_status;
913
914 user_insecure_mode = 0;
915 ignore_db = 0;
8529e0f7 916 trust_mok_list = 0;
f892ac66 917
031e5cce
SM
918 UINT64 config_sz = 0;
919 UINT8 *config_table = NULL;
920 size_t npages = 0;
921 struct mok_variable_config_entry config_template;
922
923 dprint(L"importing minimal mok state variables\n");
f892ac66
MTL
924 for (i = 0; mok_state_variables[i].name != NULL; i++) {
925 struct mok_state_variable *v = &mok_state_variables[i];
f892ac66 926
031e5cce 927 efi_status = import_one_mok_state(v, TRUE);
f892ac66 928 if (EFI_ERROR(efi_status)) {
031e5cce
SM
929 dprint(L"import_one_mok_state(ih, \"%s\", TRUE): %r\n",
930 v->rtname);
f892ac66
MTL
931 /*
932 * don't clobber EFI_SECURITY_VIOLATION from some
933 * other variable in the list.
934 */
935 if (ret != EFI_SECURITY_VIOLATION)
936 ret = efi_status;
f892ac66
MTL
937 }
938
031e5cce
SM
939 if (v->data && v->data_size) {
940 config_sz += v->data_size;
941 config_sz += sizeof(config_template);
f892ac66 942 }
031e5cce 943 }
f892ac66 944
031e5cce
SM
945 /*
946 * Alright, so we're going to copy these to a config table. The
947 * table is a packed array of N+1 struct mok_variable_config_entry
948 * items, with the last item having all zero's in name and
949 * data_size.
950 */
951 if (config_sz) {
952 config_sz += sizeof(config_template);
953 npages = ALIGN_VALUE(config_sz, PAGE_SIZE) >> EFI_PAGE_SHIFT;
954 config_table = NULL;
8529e0f7
SM
955 efi_status = BS->AllocatePages(
956 AllocateAnyPages, EfiRuntimeServicesData, npages,
957 (EFI_PHYSICAL_ADDRESS *)&config_table);
031e5cce
SM
958 if (EFI_ERROR(efi_status) || !config_table) {
959 console_print(L"Allocating %lu pages for mok config table failed: %r\n",
960 npages, efi_status);
961 config_table = NULL;
962 } else {
963 ZeroMem(config_table, npages << EFI_PAGE_SHIFT);
f892ac66 964 }
031e5cce 965 }
f892ac66 966
031e5cce
SM
967 UINT8 *p = (UINT8 *)config_table;
968 for (i = 0; p && mok_state_variables[i].name != NULL; i++) {
969 struct mok_state_variable *v = &mok_state_variables[i];
f892ac66 970
031e5cce
SM
971 ZeroMem(&config_template, sizeof(config_template));
972 strncpy(config_template.name, (CHAR8 *)v->rtname8, 255);
973 config_template.name[255] = '\0';
f892ac66 974
031e5cce 975 config_template.data_size = v->data_size;
f892ac66 976
8529e0f7
SM
977 if (v->data && v->data_size) {
978 CopyMem(p, &config_template, sizeof(config_template));
979 p += sizeof(config_template);
980 CopyMem(p, v->data, v->data_size);
981 p += v->data_size;
982 }
031e5cce
SM
983 }
984 if (p) {
985 ZeroMem(&config_template, sizeof(config_template));
986 CopyMem(p, &config_template, sizeof(config_template));
f892ac66 987
8529e0f7
SM
988 efi_status = BS->InstallConfigurationTable(&MOK_VARIABLE_STORE,
989 config_table);
031e5cce
SM
990 if (EFI_ERROR(efi_status)) {
991 console_print(L"Couldn't install MoK configuration table\n");
f892ac66
MTL
992 }
993 }
994
031e5cce
SM
995 /*
996 * This is really just to make it easy for userland.
997 */
998 dprint(L"importing full mok state variables\n");
999 for (i = 0; mok_state_variables[i].name != NULL; i++) {
1000 struct mok_state_variable *v = &mok_state_variables[i];
1001
1002 import_one_mok_state(v, FALSE);
1003 }
1004
f892ac66
MTL
1005 /*
1006 * Enter MokManager if necessary. Any actual *changes* here will
1007 * cause MokManager to demand a machine reboot, so this is safe to
1008 * have after the entire loop.
1009 */
031e5cce 1010 dprint(L"checking mok request\n");
f892ac66 1011 efi_status = check_mok_request(image_handle);
031e5cce 1012 dprint(L"mok returned %r\n", efi_status);
f892ac66 1013 if (EFI_ERROR(efi_status)) {
031e5cce
SM
1014 /*
1015 * don't clobber EFI_SECURITY_VIOLATION
1016 */
f892ac66
MTL
1017 if (ret != EFI_SECURITY_VIOLATION)
1018 ret = efi_status;
1019 return ret;
1020 }
1021
031e5cce 1022 dprint(L"returning %r\n", ret);
f892ac66
MTL
1023 return ret;
1024}
1025
031e5cce 1026// vim:fenc=utf-8:tw=75:noet