1 // SPDX-License-Identifier: BSD-2-Clause-Patent
3 * mok.c - MoK variable processing
4 * Copyright 2017 Peter Jones <pjones@redhat.com>
14 * Check if a variable exists
16 static BOOLEAN
check_var(CHAR16
*varname
)
18 EFI_STATUS efi_status
;
19 UINTN size
= sizeof(UINT32
);
23 efi_status
= gRT
->GetVariable(varname
, &SHIM_LOCK_GUID
, &attributes
,
24 &size
, (void *)&MokVar
);
25 if (!EFI_ERROR(efi_status
) || efi_status
== EFI_BUFFER_TOO_SMALL
)
31 #define SetVariable(name, guid, attrs, varsz, var) \
33 EFI_STATUS efi_status_; \
34 efi_status_ = gRT->SetVariable(name, guid, attrs, varsz, var); \
35 dprint_(L"%a:%d:%a() SetVariable(\"%s\", ... varsz=0x%llx) = %r\n", \
36 __FILE__, __LINE__ - 5, __func__, name, varsz, \
42 * If the OS has set any of these variables we need to drop into MOK and
43 * handle them appropriately
45 static EFI_STATUS
check_mok_request(EFI_HANDLE image_handle
)
47 EFI_STATUS efi_status
;
49 if (check_var(L
"MokNew") || check_var(L
"MokSB") ||
50 check_var(L
"MokPW") || check_var(L
"MokAuth") ||
51 check_var(L
"MokDel") || check_var(L
"MokDB") ||
52 check_var(L
"MokXNew") || check_var(L
"MokXDel") ||
53 check_var(L
"MokXAuth")) {
54 efi_status
= start_image(image_handle
, MOK_MANAGER
);
56 if (EFI_ERROR(efi_status
)) {
57 perror(L
"Failed to start MokManager: %r\n", efi_status
);
69 } vendor_addend_category_t
;
71 struct mok_state_variable
;
72 typedef vendor_addend_category_t (vendor_addend_categorizer_t
)(struct mok_state_variable
*);
75 * MoK variables that need to have their storage validated.
77 * The order here is important, since this is where we measure for the
80 struct mok_state_variable
{
91 * These are indirect pointers just to make initialization saner...
93 vendor_addend_categorizer_t
*categorize_addend
;
98 UINT32
*build_cert_size
;
107 static vendor_addend_category_t
108 categorize_authorized(struct mok_state_variable
*v
)
110 if (!(v
->addend
&& v
->addend_size
&&
111 *v
->addend
&& *v
->addend_size
)) {
112 return VENDOR_ADDEND_NONE
;
115 return vendor_authorized_category
;
118 static vendor_addend_category_t
119 categorize_deauthorized(struct mok_state_variable
*v
)
121 if (!(v
->addend
&& v
->addend_size
&&
122 *v
->addend
&& *v
->addend_size
)) {
123 return VENDOR_ADDEND_NONE
;
126 return VENDOR_ADDEND_DB
;
129 #define MOK_MIRROR_KEYDB 0x01
130 #define MOK_MIRROR_DELETE_FIRST 0x02
131 #define MOK_VARIABLE_MEASURE 0x04
132 #define MOK_VARIABLE_LOG 0x08
134 struct mok_state_variable mok_state_variables
[] = {
137 .rtname
= L
"MokListRT",
138 .rtname8
= "MokListRT",
139 .guid
= &SHIM_LOCK_GUID
,
140 .yes_attr
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
141 EFI_VARIABLE_NON_VOLATILE
,
142 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
143 .categorize_addend
= categorize_authorized
,
144 .addend
= &vendor_authorized
,
145 .addend_size
= &vendor_authorized_size
,
146 #if defined(ENABLE_SHIM_CERT)
147 .build_cert
= &build_cert
,
148 .build_cert_size
= &build_cert_size
,
149 #endif /* defined(ENABLE_SHIM_CERT) */
150 .flags
= MOK_MIRROR_KEYDB
|
151 MOK_MIRROR_DELETE_FIRST
|
155 {.name
= L
"MokListX",
157 .rtname
= L
"MokListXRT",
158 .rtname8
= "MokListXRT",
159 .guid
= &SHIM_LOCK_GUID
,
160 .yes_attr
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
161 EFI_VARIABLE_NON_VOLATILE
,
162 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
163 .categorize_addend
= categorize_deauthorized
,
164 .addend
= &vendor_deauthorized
,
165 .addend_size
= &vendor_deauthorized_size
,
166 .flags
= MOK_MIRROR_KEYDB
|
167 MOK_MIRROR_DELETE_FIRST
|
171 {.name
= L
"MokSBState",
172 .name8
= "MokSBState",
173 .rtname
= L
"MokSBStateRT",
174 .rtname8
= "MokSBStateRT",
175 .guid
= &SHIM_LOCK_GUID
,
176 .yes_attr
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
177 EFI_VARIABLE_NON_VOLATILE
,
178 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
179 .flags
= MOK_MIRROR_DELETE_FIRST
|
180 MOK_VARIABLE_MEASURE
|
183 .state
= &user_insecure_mode
,
185 {.name
= L
"MokDBState",
186 .name8
= "MokDBState",
187 .rtname
= L
"MokIgnoreDB",
188 .rtname8
= "MokIgnoreDB",
189 .guid
= &SHIM_LOCK_GUID
,
190 .yes_attr
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
191 EFI_VARIABLE_NON_VOLATILE
,
192 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
198 #define should_mirror_addend(v) (((v)->categorize_addend) && ((v)->categorize_addend(v) != VENDOR_ADDEND_NONE))
200 static inline BOOLEAN
nonnull(1)
201 should_mirror_build_cert(struct mok_state_variable
*v
)
203 return (v
->build_cert
&& v
->build_cert_size
&&
204 *v
->build_cert
&& *v
->build_cert_size
) ? TRUE
: FALSE
;
207 static const uint8_t null_sha256
[32] = { 0, };
209 typedef UINTN SIZE_T
;
212 get_max_var_sz(UINT32 attrs
, SIZE_T
*max_var_szp
)
214 EFI_STATUS efi_status
;
215 uint64_t max_storage_sz
= 0;
216 uint64_t remaining_sz
= 0;
217 uint64_t max_var_sz
= 0;
220 efi_status
= gRT
->QueryVariableInfo(attrs
, &max_storage_sz
,
221 &remaining_sz
, &max_var_sz
);
222 if (EFI_ERROR(efi_status
)) {
223 perror(L
"Could not get variable storage info: %r\n", efi_status
);
228 * I just don't trust implementations to not be showing static data
231 *max_var_szp
= (max_var_sz
< remaining_sz
) ? max_var_sz
: remaining_sz
;
232 dprint("max_var_sz:%lx remaining_sz:%lx max_storage_sz:%lx\n",
233 max_var_sz
, remaining_sz
, max_storage_sz
);
238 * If any entries fit in < maxsz, and nothing goes wrong, create a variable
239 * of the given name and guid with as many esd entries as possible in it,
240 * and updates *esdp with what would be the next entry (even if makes *esdp
241 * > esl+esl->SignatureListSize), and returns whatever SetVariable()
244 * If no entries fit (i.e. sizeof(esl) + esl->SignatureSize > maxsz),
245 * returns EFI_BUFFER_TOO_SMALL;
248 mirror_one_esl(CHAR16
*name
, EFI_GUID
*guid
, UINT32 attrs
,
249 EFI_SIGNATURE_LIST
*esl
, EFI_SIGNATURE_DATA
*esd
,
250 UINTN
*newsz
, SIZE_T maxsz
)
252 EFI_STATUS efi_status
;
253 SIZE_T howmany
, varsz
= 0, esdsz
;
256 howmany
= MIN((maxsz
- sizeof(*esl
)) / esl
->SignatureSize
,
257 (esl
->SignatureListSize
- sizeof(*esl
)) / esl
->SignatureSize
);
259 return EFI_BUFFER_TOO_SMALL
;
263 * We always assume esl->SignatureHeaderSize is 0 (and so far,
264 * that's true as per UEFI 2.8)
266 esdsz
= howmany
* esl
->SignatureSize
;
268 dprint(L
"Trying to add %lx signatures to \"%s\" of size %lx\n",
269 howmany
, name
, esl
->SignatureSize
);
272 * Because of the semantics of variable_create_esl(), the first
273 * owner guid from the data is not part of esdsz, or the data.
277 efi_status
= variable_create_esl(data
+ sizeof(EFI_GUID
),
278 esdsz
- sizeof(EFI_GUID
),
280 &esd
->SignatureOwner
,
282 if (EFI_ERROR(efi_status
) || !var
|| !varsz
) {
283 LogError(L
"Couldn't allocate %lu bytes for mok variable \"%s\": %r\n",
284 varsz
, var
, efi_status
);
288 dprint(L
"new esl:\n");
289 dhexdumpat(var
, varsz
, 0);
291 efi_status
= SetVariable(name
, guid
, attrs
, varsz
, var
);
293 if (EFI_ERROR(efi_status
)) {
294 LogError(L
"Couldn't create mok variable \"%s\": %r\n",
295 varsz
, var
, efi_status
);
305 mirror_mok_db(CHAR16
*name
, CHAR8
*name8
, EFI_GUID
*guid
, UINT32 attrs
,
306 UINT8
*FullData
, SIZE_T FullDataSize
, BOOLEAN only_first
)
308 EFI_STATUS efi_status
= EFI_SUCCESS
;
312 efi_status
= get_max_var_sz(attrs
, &max_var_sz
);
313 if (EFI_ERROR(efi_status
)) {
314 LogError(L
"Could not get maximum variable size: %r",
319 if (FullDataSize
<= max_var_sz
) {
320 efi_status
= SetVariable(name
, guid
, attrs
,
321 FullDataSize
, FullData
);
328 UINTN namelen
, namesz
;
330 namelen
= StrLen(name
);
331 namesz
= namelen
* 2;
338 namen
= AllocateZeroPool(namesz
);
340 LogError(L
"Could not allocate %lu bytes", namesz
);
341 return EFI_OUT_OF_RESOURCES
;
343 namen8
= AllocateZeroPool(namelen
);
346 LogError(L
"Could not allocate %lu bytes", namelen
);
347 return EFI_OUT_OF_RESOURCES
;
352 const SIZE_T minsz
= sizeof(EFI_SIGNATURE_LIST
)
353 + sizeof(EFI_SIGNATURE_DATA
)
355 BOOLEAN did_one
= FALSE
;
358 * Create any entries that can fit.
361 dprint(L
"full data for \"%s\":\n", name
);
362 dhexdumpat(FullData
, FullDataSize
, 0);
364 EFI_SIGNATURE_LIST
*esl
= NULL
;
365 UINTN esl_end_pos
= 0;
366 for (i
= 0, pos
= 0; FullDataSize
- pos
>= minsz
&& FullData
; ) {
367 EFI_SIGNATURE_DATA
*esd
= NULL
;
369 dprint(L
"pos:0x%llx FullDataSize:0x%llx\n", pos
, FullDataSize
);
370 if (esl
== NULL
|| pos
>= esl_end_pos
) {
371 UINT8
*nesl
= FullData
+ pos
;
372 dprint(L
"esl:0x%llx->0x%llx\n", esl
, nesl
);
373 esl
= (EFI_SIGNATURE_LIST
*)nesl
;
374 esl_end_pos
= pos
+ esl
->SignatureListSize
;
375 dprint(L
"pos:0x%llx->0x%llx\n", pos
, pos
+ sizeof(*esl
));
378 esd
= (EFI_SIGNATURE_DATA
*)(FullData
+ pos
);
379 if (pos
>= FullDataSize
)
381 if (esl
->SignatureListSize
== 0 || esl
->SignatureSize
== 0)
384 dprint(L
"esl[%lu] 0x%llx = {sls=0x%lx, ss=0x%lx} esd:0x%llx\n",
385 i
, esl
, esl
->SignatureListSize
, esl
->SignatureSize
, esd
);
388 SPrint(namen
, namelen
, L
"%s%lu", name
, i
);
389 namen
[namelen
-1] = 0;
392 for (j
= 0; j
< namelen
; j
++)
393 namen8
[j
] = (CHAR8
)(namen
[j
] & 0xff);
394 namen8
[namelen
- 1] = 0;
398 * In case max_var_sz is computed dynamically, refresh the
401 efi_status
= get_max_var_sz(attrs
, &max_var_sz
);
402 if (EFI_ERROR(efi_status
)) {
403 LogError(L
"Could not get maximum variable size: %r",
414 howmany
= MIN((max_var_sz
- sizeof(*esl
)) / esl
->SignatureSize
,
415 (esl
->SignatureListSize
- sizeof(*esl
)) / esl
->SignatureSize
);
416 if (!only_first
&& i
== 0 && howmany
>= 1) {
417 adj
= howmany
* esl
->SignatureSize
;
418 dprint(L
"pos:0x%llx->0x%llx\n", pos
, pos
+ adj
);
425 efi_status
= mirror_one_esl(namen
, guid
, attrs
,
426 esl
, esd
, &adj
, max_var_sz
);
427 dprint(L
"esd:0x%llx adj:0x%llx\n", esd
, adj
);
428 if (EFI_ERROR(efi_status
) && efi_status
!= EFI_BUFFER_TOO_SMALL
) {
429 LogError(L
"Could not mirror mok variable \"%s\": %r\n",
434 if (!EFI_ERROR(efi_status
)) {
438 dprint(L
"pos:0x%llx->0x%llx\n", pos
, pos
+ adj
);
444 if (only_first
&& !did_one
) {
446 * In this case we're going to try to create a
447 * dummy variable so that there's one there. It
448 * may or may not work, because on some firmware
449 * builds when the SetVariable call above fails it
450 * does actually set the variable(!), so aside from
451 * not using the allocation if it doesn't work, we
452 * don't care about failures here.
457 efi_status
= variable_create_esl(
458 null_sha256
, sizeof(null_sha256
),
459 &EFI_CERT_SHA256_GUID
, &SHIM_LOCK_GUID
,
462 * from here we don't really care if it works or
465 if (!EFI_ERROR(efi_status
) && var
&& varsz
) {
466 SetVariable(name
, guid
,
467 EFI_VARIABLE_BOOTSERVICE_ACCESS
468 | EFI_VARIABLE_RUNTIME_ACCESS
,
472 efi_status
= EFI_INVALID_PARAMETER
;
473 } else if (EFI_ERROR(efi_status
)) {
474 perror(L
"Failed to set %s: %r\n", name
, efi_status
);
480 static EFI_STATUS
nonnull(1)
481 mirror_one_mok_variable(struct mok_state_variable
*v
,
484 EFI_STATUS efi_status
= EFI_SUCCESS
;
485 uint8_t *FullData
= NULL
;
486 size_t FullDataSize
= 0;
487 vendor_addend_category_t addend_category
= VENDOR_ADDEND_NONE
;
489 uint32_t attrs
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
490 EFI_VARIABLE_RUNTIME_ACCESS
;
491 BOOLEAN measure
= v
->flags
& MOK_VARIABLE_MEASURE
;
492 BOOLEAN log
= v
->flags
& MOK_VARIABLE_LOG
;
493 size_t build_cert_esl_sz
= 0, addend_esl_sz
= 0;
496 if (v
->categorize_addend
)
497 addend_category
= v
->categorize_addend(v
);
500 * if it is, there's more data
502 if (v
->flags
& MOK_MIRROR_KEYDB
) {
505 * We're mirroring (into) an efi security database, aka an
506 * array of EFI_SIGNATURE_LIST. Its layout goes like:
508 * existing_variable_data
509 * existing_variable_data_size
510 * if flags & MOK_MIRROR_KEYDB
513 * build_cert_header (always sz=0)
514 * build_cert_esd[0] { owner, data }
515 * if addend==vendor_db
518 * vendor_db_header_n (always sz=0)
519 * vendor_db_esd_n[m] {{ owner, data }, ... }
520 * elif addend==vendor_cert
522 * vendor_cert_header (always sz=0)
523 * vendor_cert_esd[1] { owner, data }
525 * first we determine the size of the variable, then alloc
530 * *first* vendor_db or vendor_cert
532 switch (addend_category
) {
533 case VENDOR_ADDEND_DB
:
535 * if it's an ESL already, we use it wholesale
537 FullDataSize
+= *v
->addend_size
;
538 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
539 FullDataSize
, FullData
);
541 case VENDOR_ADDEND_X509
:
542 efi_status
= fill_esl(*v
->addend
, *v
->addend_size
,
543 &EFI_CERT_TYPE_X509_GUID
,
545 NULL
, &addend_esl_sz
);
546 if (efi_status
!= EFI_BUFFER_TOO_SMALL
) {
547 perror(L
"Could not add built-in cert to %s: %r\n",
548 v
->name
, efi_status
);
551 FullDataSize
+= addend_esl_sz
;
552 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
553 FullDataSize
, FullData
);
556 case VENDOR_ADDEND_NONE
:
557 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
558 FullDataSize
, FullData
);
563 * then the build cert if it's there
565 if (should_mirror_build_cert(v
)) {
566 efi_status
= fill_esl(*v
->build_cert
,
568 &EFI_CERT_TYPE_X509_GUID
,
570 NULL
, &build_cert_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
);
576 FullDataSize
+= build_cert_esl_sz
;
577 dprint(L
"FullDataSize:0x%lx FullData:0x%llx\n",
578 FullDataSize
, FullData
);
584 * we're always mirroring the original data, whether this is an efi
585 * security database or not
587 dprint(L
"v->name:\"%s\" v->rtname:\"%s\"\n", v
->name
, v
->rtname
);
588 dprint(L
"v->data_size:%lu v->data:0x%llx\n", v
->data_size
, v
->data
);
589 dprint(L
"FullDataSize:%lu FullData:0x%llx\n", FullDataSize
, FullData
);
591 FullDataSize
+= v
->data_size
;
592 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
593 FullDataSize
, FullData
);
595 if (v
->data_size
== FullDataSize
)
599 * Now we have the full size
603 * allocate the buffer, or use the old one if it's just the
606 if (FullDataSize
== v
->data_size
) {
608 FullDataSize
= v
->data_size
;
609 p
= FullData
+ FullDataSize
;
610 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
611 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
615 dprint(L
"FullDataSize:%lu FullData:0x%llx allocating FullData\n",
616 FullDataSize
, FullData
);
618 * make sure we've got some zeroes at the end, just
623 allocsz
= FullDataSize
+ sizeof(EFI_SIGNATURE_LIST
);
624 new = ALIGN_VALUE(allocsz
, 4096);
625 allocsz
= new == allocsz
? new + 4096 : new;
626 FullData
= AllocateZeroPool(allocsz
);
628 perror(L
"Failed to allocate %lu bytes for %s\n",
629 FullDataSize
, v
->name
);
630 return EFI_OUT_OF_RESOURCES
;
635 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
636 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
641 if (v
->flags
& MOK_MIRROR_KEYDB
) {
643 * first vendor_cert or vendor_db
645 switch (addend_category
) {
646 case VENDOR_ADDEND_DB
:
647 CopyMem(p
, *v
->addend
, *v
->addend_size
);
648 p
+= *v
->addend_size
;
649 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
650 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
652 case VENDOR_ADDEND_X509
:
653 efi_status
= fill_esl(*v
->addend
, *v
->addend_size
,
654 &EFI_CERT_TYPE_X509_GUID
,
657 if (EFI_ERROR(efi_status
)) {
658 perror(L
"Could not add built-in cert to %s: %r\n",
659 v
->name
, efi_status
);
663 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
664 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
667 case VENDOR_ADDEND_NONE
:
668 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
669 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
674 * then is the build cert
676 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
677 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
678 if (should_mirror_build_cert(v
)) {
679 efi_status
= fill_esl(*v
->build_cert
,
681 &EFI_CERT_TYPE_X509_GUID
,
683 p
, &build_cert_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
);
689 p
+= build_cert_esl_sz
;
690 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
691 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
696 * last bit is existing data, unless it's the only thing,
697 * in which case it's already there.
700 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
701 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
702 if (v
->data
&& v
->data_size
) {
703 CopyMem(p
, v
->data
, v
->data_size
);
706 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
707 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
711 * We always want to create our key databases, so in this case we
714 if ((v
->flags
& MOK_MIRROR_KEYDB
) && FullDataSize
== 0) {
715 efi_status
= variable_create_esl(
716 null_sha256
, sizeof(null_sha256
),
717 &EFI_CERT_SHA256_GUID
, &SHIM_LOCK_GUID
,
718 &FullData
, &FullDataSize
);
719 if (EFI_ERROR(efi_status
)) {
720 perror(L
"Failed to allocate %lu bytes for %s\n",
721 FullDataSize
, v
->name
);
724 p
= FullData
+ FullDataSize
;
725 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
726 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
729 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
730 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
731 if (FullDataSize
&& v
->flags
& MOK_MIRROR_KEYDB
) {
732 dprint(L
"calling mirror_mok_db(\"%s\", datasz=%lu)\n",
733 v
->rtname
, FullDataSize
);
734 efi_status
= mirror_mok_db(v
->rtname
, (CHAR8
*)v
->rtname8
, v
->guid
,
735 attrs
, FullData
, FullDataSize
,
737 dprint(L
"mirror_mok_db(\"%s\", datasz=%lu) returned %r\n",
738 v
->rtname
, FullDataSize
, efi_status
);
739 } else if (FullDataSize
&& only_first
) {
740 efi_status
= SetVariable(v
->rtname
, v
->guid
, attrs
,
741 FullDataSize
, FullData
);
743 if (FullDataSize
&& only_first
) {
746 * Measure this into PCR 7 in the Microsoft format
748 efi_status
= tpm_measure_variable(v
->name
, *v
->guid
,
749 FullDataSize
, FullData
);
750 if (EFI_ERROR(efi_status
)) {
751 dprint(L
"tpm_measure_variable(\"%s\",%lu,0x%llx)->%r\n",
752 v
->name
, FullDataSize
, FullData
, efi_status
);
759 * Log this variable into whichever PCR the table
762 EFI_PHYSICAL_ADDRESS datap
=
763 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FullData
,
764 efi_status
= tpm_log_event(datap
, FullDataSize
,
765 v
->pcr
, (CHAR8
*)v
->name8
);
766 if (EFI_ERROR(efi_status
)) {
767 dprint(L
"tpm_log_event(0x%llx, %lu, %lu, \"%s\")->%r\n",
768 FullData
, FullDataSize
, v
->pcr
, v
->name
,
775 if (v
->data
&& v
->data_size
&& v
->data
!= FullData
) {
781 v
->data_size
= FullDataSize
;
782 dprint(L
"returning %r\n", efi_status
);
787 * Mirror a variable if it has an rtname, and preserve any
788 * EFI_SECURITY_VIOLATION status at the same time.
790 static EFI_STATUS
nonnull(1)
791 maybe_mirror_one_mok_variable(struct mok_state_variable
*v
,
792 EFI_STATUS ret
, BOOLEAN only_first
)
794 EFI_STATUS efi_status
;
795 BOOLEAN present
= FALSE
;
798 if (!only_first
&& (v
->flags
& MOK_MIRROR_DELETE_FIRST
)) {
799 dprint(L
"deleting \"%s\"\n", v
->rtname
);
800 efi_status
= LibDeleteVariable(v
->rtname
, v
->guid
);
801 dprint(L
"LibDeleteVariable(\"%s\",...) => %r\n", v
->rtname
, efi_status
);
804 efi_status
= mirror_one_mok_variable(v
, only_first
);
805 if (EFI_ERROR(efi_status
)) {
806 if (ret
!= EFI_SECURITY_VIOLATION
)
808 perror(L
"Could not create %s: %r\n", v
->rtname
,
813 present
= (v
->data
&& v
->data_size
) ? TRUE
: FALSE
;
817 if (v
->data_size
== sizeof(UINT8
) && v
->state
) {
818 *v
->state
= v
->data
[0];
824 struct mok_variable_config_entry
{
830 EFI_STATUS
import_one_mok_state(struct mok_state_variable
*v
,
833 EFI_STATUS ret
= EFI_SUCCESS
;
834 EFI_STATUS efi_status
;
836 user_insecure_mode
= 0;
840 BOOLEAN
delete = FALSE
;
842 dprint(L
"importing mok state for \"%s\"\n", v
->name
);
844 efi_status
= get_variable_attr(v
->name
,
845 &v
->data
, &v
->data_size
,
847 if (efi_status
== EFI_NOT_FOUND
) {
850 } else if (EFI_ERROR(efi_status
)) {
851 perror(L
"Could not verify %s: %r\n", v
->name
,
855 if (!(attrs
& v
->yes_attr
)) {
856 perror(L
"Variable %s is missing attributes:\n",
858 perror(L
" 0x%08x should have 0x%08x set.\n",
862 if (attrs
& v
->no_attr
) {
863 perror(L
"Variable %s has incorrect attribute:\n",
865 perror(L
" 0x%08x should not have 0x%08x set.\n",
870 if (delete == TRUE
) {
871 perror(L
"Deleting bad variable %s\n", v
->name
);
872 efi_status
= LibDeleteVariable(v
->name
, v
->guid
);
873 if (EFI_ERROR(efi_status
)) {
874 perror(L
"Failed to erase %s\n", v
->name
);
875 ret
= EFI_SECURITY_VIOLATION
;
882 dprint(L
"maybe mirroring \"%s\". original data:\n", v
->name
);
883 dhexdumpat(v
->data
, v
->data_size
, 0);
885 ret
= maybe_mirror_one_mok_variable(v
, ret
, only_first
);
886 dprint(L
"returning %r\n", ret
);
891 * Verify our non-volatile MoK state. This checks the variables above
892 * accessable and have valid attributes. If they don't, it removes
893 * them. If any of them can't be removed, our ability to do this is
894 * comprimized, so return EFI_SECURITY_VIOLATION.
896 * Any variable that isn't deleted and has ->measure == TRUE is then
897 * measured into the tpm.
899 * Any variable with a ->rtname element is then mirrored to a
900 * runtime-accessable version. The new ones won't be marked NV, so the OS
903 EFI_STATUS
import_mok_state(EFI_HANDLE image_handle
)
906 EFI_STATUS ret
= EFI_SUCCESS
;
907 EFI_STATUS efi_status
;
909 user_insecure_mode
= 0;
912 UINT64 config_sz
= 0;
913 UINT8
*config_table
= NULL
;
915 struct mok_variable_config_entry config_template
;
917 dprint(L
"importing minimal mok state variables\n");
918 for (i
= 0; mok_state_variables
[i
].name
!= NULL
; i
++) {
919 struct mok_state_variable
*v
= &mok_state_variables
[i
];
921 efi_status
= import_one_mok_state(v
, TRUE
);
922 if (EFI_ERROR(efi_status
)) {
923 dprint(L
"import_one_mok_state(ih, \"%s\", TRUE): %r\n",
926 * don't clobber EFI_SECURITY_VIOLATION from some
927 * other variable in the list.
929 if (ret
!= EFI_SECURITY_VIOLATION
)
933 if (v
->data
&& v
->data_size
) {
934 config_sz
+= v
->data_size
;
935 config_sz
+= sizeof(config_template
);
940 * Alright, so we're going to copy these to a config table. The
941 * table is a packed array of N+1 struct mok_variable_config_entry
942 * items, with the last item having all zero's in name and
946 config_sz
+= sizeof(config_template
);
947 npages
= ALIGN_VALUE(config_sz
, PAGE_SIZE
) >> EFI_PAGE_SHIFT
;
949 efi_status
= gBS
->AllocatePages(AllocateAnyPages
,
950 EfiRuntimeServicesData
,
952 (EFI_PHYSICAL_ADDRESS
*)&config_table
);
953 if (EFI_ERROR(efi_status
) || !config_table
) {
954 console_print(L
"Allocating %lu pages for mok config table failed: %r\n",
958 ZeroMem(config_table
, npages
<< EFI_PAGE_SHIFT
);
962 UINT8
*p
= (UINT8
*)config_table
;
963 for (i
= 0; p
&& mok_state_variables
[i
].name
!= NULL
; i
++) {
964 struct mok_state_variable
*v
= &mok_state_variables
[i
];
966 ZeroMem(&config_template
, sizeof(config_template
));
967 strncpya(config_template
.name
, (CHAR8
*)v
->rtname8
, 255);
968 config_template
.name
[255] = '\0';
970 config_template
.data_size
= v
->data_size
;
972 CopyMem(p
, &config_template
, sizeof(config_template
));
973 p
+= sizeof(config_template
);
974 CopyMem(p
, v
->data
, v
->data_size
);
978 ZeroMem(&config_template
, sizeof(config_template
));
979 CopyMem(p
, &config_template
, sizeof(config_template
));
981 efi_status
= gBS
->InstallConfigurationTable(&MOK_VARIABLE_STORE
,
983 if (EFI_ERROR(efi_status
)) {
984 console_print(L
"Couldn't install MoK configuration table\n");
989 * This is really just to make it easy for userland.
991 dprint(L
"importing full mok state variables\n");
992 for (i
= 0; mok_state_variables
[i
].name
!= NULL
; i
++) {
993 struct mok_state_variable
*v
= &mok_state_variables
[i
];
995 import_one_mok_state(v
, FALSE
);
999 * Enter MokManager if necessary. Any actual *changes* here will
1000 * cause MokManager to demand a machine reboot, so this is safe to
1001 * have after the entire loop.
1003 dprint(L
"checking mok request\n");
1004 efi_status
= check_mok_request(image_handle
);
1005 dprint(L
"mok returned %r\n", efi_status
);
1006 if (EFI_ERROR(efi_status
)) {
1008 * don't clobber EFI_SECURITY_VIOLATION
1010 if (ret
!= EFI_SECURITY_VIOLATION
)
1015 dprint(L
"returning %r\n", ret
);
1019 // vim:fenc=utf-8:tw=75:noet