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