1 // SPDX-License-Identifier: BSD-2-Clause-Patent
3 * mok.c - MoK variable processing
4 * Copyright 2017 Peter Jones <pjones@redhat.com>
10 * Check if a variable exists
12 static BOOLEAN
check_var(CHAR16
*varname
)
14 EFI_STATUS efi_status
;
15 UINTN size
= sizeof(UINT32
);
19 efi_status
= gRT
->GetVariable(varname
, &SHIM_LOCK_GUID
, &attributes
,
20 &size
, (void *)&MokVar
);
21 if (!EFI_ERROR(efi_status
) || efi_status
== EFI_BUFFER_TOO_SMALL
)
27 #define SetVariable(name, guid, attrs, varsz, var) \
29 EFI_STATUS efi_status_; \
30 efi_status_ = gRT->SetVariable(name, guid, attrs, varsz, var); \
31 dprint_(L"%a:%d:%a() SetVariable(\"%s\", ... varsz=0x%llx) = %r\n", \
32 __FILE__, __LINE__ - 5, __func__, name, varsz, \
38 * If the OS has set any of these variables we need to drop into MOK and
39 * handle them appropriately
41 static EFI_STATUS
check_mok_request(EFI_HANDLE image_handle
)
43 EFI_STATUS efi_status
;
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") ||
49 check_var(L
"MokXAuth")) {
50 efi_status
= start_image(image_handle
, MOK_MANAGER
);
52 if (EFI_ERROR(efi_status
)) {
53 perror(L
"Failed to start MokManager: %r\n", efi_status
);
65 } vendor_addend_category_t
;
67 struct mok_state_variable
;
68 typedef vendor_addend_category_t (vendor_addend_categorizer_t
)(struct mok_state_variable
*);
71 * MoK variables that need to have their storage validated.
73 * The order here is important, since this is where we measure for the
76 struct mok_state_variable
{
77 CHAR16
*name
; /* UCS-2 BS|NV variable name */
78 char *name8
; /* UTF-8 BS|NV variable name */
79 CHAR16
*rtname
; /* UCS-2 RT variable name */
80 char *rtname8
; /* UTF-8 RT variable name */
81 EFI_GUID
*guid
; /* variable GUID */
84 * these are used during processing, they shouldn't be filled out
85 * in the static table below.
91 * addend are added to the input variable, as part of the runtime
92 * variable, so that they're visible to the kernel. These are
93 * where we put vendor_cert / vendor_db / vendor_dbx
95 * These are indirect pointers just to make initialization saner...
97 vendor_addend_categorizer_t
*categorize_addend
; /* determines format */
99 * we call categorize_addend() and it determines what kind of thing
100 * this is. That is, if this shim was built with VENDOR_CERT, for
101 * the DB entry it'll return VENDOR_ADDEND_X509; if you used
102 * VENDOR_DB instead, it'll return VENDOR_ADDEND_DB. If you used
103 * neither, it'll do VENDOR_ADDEND_NONE.
105 * The existing categorizers are for db and dbx; they differ
106 * because we don't currently support a CERT for dbx.
112 * build_cert is our build-time cert. Like addend, this is added
113 * to the input variable, as part of the runtime variable, so that
114 * they're visible to the kernel. This is the ephemeral cert used
115 * for signing MokManager.efi and fallback.efi.
117 * These are indirect pointers just to make initialization saner...
120 UINT32
*build_cert_size
;
122 UINT32 yes_attr
; /* var attrs that must be set */
123 UINT32 no_attr
; /* var attrs that must not be set */
124 UINT32 flags
; /* flags on what and how to mirror */
126 * MOK_MIRROR_KEYDB mirror this as a key database
127 * MOK_MIRROR_DELETE_FIRST delete any existing variable first
128 * MOK_VARIABLE_MEASURE extend PCR 7 and log the hash change
129 * MOK_VARIABLE_LOG measure into whatever .pcr says and log
131 UINTN pcr
; /* PCR to measure and hash to */
134 * if this is a state value, a pointer to our internal state to be
140 static vendor_addend_category_t
141 categorize_authorized(struct mok_state_variable
*v
)
143 if (!(v
->addend
&& v
->addend_size
&&
144 *v
->addend
&& *v
->addend_size
)) {
145 return VENDOR_ADDEND_NONE
;
148 return vendor_authorized_category
;
151 static vendor_addend_category_t
152 categorize_deauthorized(struct mok_state_variable
*v
)
154 if (!(v
->addend
&& v
->addend_size
&&
155 *v
->addend
&& *v
->addend_size
)) {
156 return VENDOR_ADDEND_NONE
;
159 return VENDOR_ADDEND_DB
;
162 #define MOK_MIRROR_KEYDB 0x01
163 #define MOK_MIRROR_DELETE_FIRST 0x02
164 #define MOK_VARIABLE_MEASURE 0x04
165 #define MOK_VARIABLE_LOG 0x08
167 struct mok_state_variable mok_state_variables
[] = {
170 .rtname
= L
"MokListRT",
171 .rtname8
= "MokListRT",
172 .guid
= &SHIM_LOCK_GUID
,
173 .yes_attr
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
174 EFI_VARIABLE_NON_VOLATILE
,
175 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
176 .categorize_addend
= categorize_authorized
,
177 .addend
= &vendor_authorized
,
178 .addend_size
= &vendor_authorized_size
,
179 #if defined(ENABLE_SHIM_CERT)
180 .build_cert
= &build_cert
,
181 .build_cert_size
= &build_cert_size
,
182 #endif /* defined(ENABLE_SHIM_CERT) */
183 .flags
= MOK_MIRROR_KEYDB
|
184 MOK_MIRROR_DELETE_FIRST
|
188 {.name
= L
"MokListX",
190 .rtname
= L
"MokListXRT",
191 .rtname8
= "MokListXRT",
192 .guid
= &SHIM_LOCK_GUID
,
193 .yes_attr
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
194 EFI_VARIABLE_NON_VOLATILE
,
195 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
196 .categorize_addend
= categorize_deauthorized
,
197 .addend
= &vendor_deauthorized
,
198 .addend_size
= &vendor_deauthorized_size
,
199 .flags
= MOK_MIRROR_KEYDB
|
200 MOK_MIRROR_DELETE_FIRST
|
204 {.name
= L
"MokSBState",
205 .name8
= "MokSBState",
206 .rtname
= L
"MokSBStateRT",
207 .rtname8
= "MokSBStateRT",
208 .guid
= &SHIM_LOCK_GUID
,
209 .yes_attr
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
210 EFI_VARIABLE_NON_VOLATILE
,
211 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
212 .flags
= MOK_MIRROR_DELETE_FIRST
|
213 MOK_VARIABLE_MEASURE
|
216 .state
= &user_insecure_mode
,
218 {.name
= L
"MokDBState",
219 .name8
= "MokDBState",
220 .rtname
= L
"MokIgnoreDB",
221 .rtname8
= "MokIgnoreDB",
222 .guid
= &SHIM_LOCK_GUID
,
223 .yes_attr
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
224 EFI_VARIABLE_NON_VOLATILE
,
225 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
228 {.name
= SBAT_VAR_NAME
,
229 .name8
= SBAT_VAR_NAME8
,
230 .rtname
= SBAT_RT_VAR_NAME
,
231 .rtname8
= SBAT_RT_VAR_NAME8
,
232 .guid
= &SHIM_LOCK_GUID
,
233 .yes_attr
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
234 EFI_VARIABLE_NON_VOLATILE
,
236 * we're enforcing that SBAT can't have an RT flag here because
237 * there's no way to tell whether it's an authenticated variable.
239 #if !defined(ENABLE_SHIM_DEVEL)
240 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
244 .flags
= MOK_MIRROR_DELETE_FIRST
|
245 MOK_VARIABLE_MEASURE
,
251 #define should_mirror_addend(v) (((v)->categorize_addend) && ((v)->categorize_addend(v) != VENDOR_ADDEND_NONE))
253 static inline BOOLEAN
NONNULL(1)
254 should_mirror_build_cert(struct mok_state_variable
*v
)
256 return (v
->build_cert
&& v
->build_cert_size
&&
257 *v
->build_cert
&& *v
->build_cert_size
) ? TRUE
: FALSE
;
260 static const uint8_t null_sha256
[32] = { 0, };
262 typedef UINTN SIZE_T
;
265 get_max_var_sz(UINT32 attrs
, SIZE_T
*max_var_szp
)
267 EFI_STATUS efi_status
;
268 uint64_t max_storage_sz
= 0;
269 uint64_t remaining_sz
= 0;
270 uint64_t max_var_sz
= 0;
273 efi_status
= gRT
->QueryVariableInfo(attrs
, &max_storage_sz
,
274 &remaining_sz
, &max_var_sz
);
275 if (EFI_ERROR(efi_status
)) {
276 perror(L
"Could not get variable storage info: %r\n", efi_status
);
281 * I just don't trust implementations to not be showing static data
284 *max_var_szp
= (max_var_sz
< remaining_sz
) ? max_var_sz
: remaining_sz
;
285 dprint("max_var_sz:%lx remaining_sz:%lx max_storage_sz:%lx\n",
286 max_var_sz
, remaining_sz
, max_storage_sz
);
291 * If any entries fit in < maxsz, and nothing goes wrong, create a variable
292 * of the given name and guid with as many esd entries as possible in it,
293 * and updates *esdp with what would be the next entry (even if makes *esdp
294 * > esl+esl->SignatureListSize), and returns whatever SetVariable()
297 * If no entries fit (i.e. sizeof(esl) + esl->SignatureSize > maxsz),
298 * returns EFI_BUFFER_TOO_SMALL;
301 mirror_one_esl(CHAR16
*name
, EFI_GUID
*guid
, UINT32 attrs
,
302 EFI_SIGNATURE_LIST
*esl
, EFI_SIGNATURE_DATA
*esd
,
305 EFI_STATUS efi_status
;
310 * We always assume esl->SignatureHeaderSize is 0 (and so far,
311 * that's true as per UEFI 2.8)
313 dprint(L
"Trying to add %lx signatures to \"%s\" of size %lx\n",
314 howmany
, name
, esl
->SignatureSize
);
317 * Because of the semantics of variable_create_esl(), the first
318 * owner guid from the data is not part of esdsz, or the data.
322 efi_status
= variable_create_esl(esd
, howmany
,
326 if (EFI_ERROR(efi_status
) || !var
|| !varsz
) {
327 LogError(L
"Couldn't allocate %lu bytes for mok variable \"%s\": %r\n",
328 varsz
, var
, efi_status
);
332 dprint(L
"new esl:\n");
333 dhexdumpat(var
, varsz
, 0);
335 efi_status
= SetVariable(name
, guid
, attrs
, varsz
, var
);
337 if (EFI_ERROR(efi_status
)) {
338 LogError(L
"Couldn't create mok variable \"%s\": %r\n",
339 varsz
, var
, efi_status
);
347 mirror_mok_db(CHAR16
*name
, CHAR8
*name8
, EFI_GUID
*guid
, UINT32 attrs
,
348 UINT8
*FullData
, SIZE_T FullDataSize
, BOOLEAN only_first
)
350 EFI_STATUS efi_status
= EFI_SUCCESS
;
353 efi_status
= get_max_var_sz(attrs
, &max_var_sz
);
354 if (EFI_ERROR(efi_status
)) {
355 LogError(L
"Could not get maximum variable size: %r",
360 if (FullDataSize
<= max_var_sz
) {
362 efi_status
= SetVariable(name
, guid
, attrs
,
363 FullDataSize
, FullData
);
370 UINTN namelen
, namesz
;
372 namelen
= StrLen(name
);
373 namesz
= namelen
* 2;
380 namen
= AllocateZeroPool(namesz
);
382 LogError(L
"Could not allocate %lu bytes", namesz
);
383 return EFI_OUT_OF_RESOURCES
;
385 namen8
= AllocateZeroPool(namelen
);
388 LogError(L
"Could not allocate %lu bytes", namelen
);
389 return EFI_OUT_OF_RESOURCES
;
394 const SIZE_T minsz
= sizeof(EFI_SIGNATURE_LIST
)
395 + sizeof(EFI_SIGNATURE_DATA
)
397 BOOLEAN did_one
= FALSE
;
400 * Create any entries that can fit.
403 dprint(L
"full data for \"%s\":\n", name
);
404 dhexdumpat(FullData
, FullDataSize
, 0);
406 EFI_SIGNATURE_LIST
*esl
= NULL
;
407 UINTN esl_end_pos
= 0;
408 for (i
= 0, pos
= 0; FullDataSize
- pos
>= minsz
&& FullData
; ) {
409 EFI_SIGNATURE_DATA
*esd
= NULL
;
411 dprint(L
"pos:0x%llx FullDataSize:0x%llx\n", pos
, FullDataSize
);
412 if (esl
== NULL
|| pos
>= esl_end_pos
) {
413 UINT8
*nesl
= FullData
+ pos
;
414 dprint(L
"esl:0x%llx->0x%llx\n", esl
, nesl
);
415 esl
= (EFI_SIGNATURE_LIST
*)nesl
;
416 esl_end_pos
= pos
+ esl
->SignatureListSize
;
417 dprint(L
"pos:0x%llx->0x%llx\n", pos
, pos
+ sizeof(*esl
));
420 esd
= (EFI_SIGNATURE_DATA
*)(FullData
+ pos
);
421 if (pos
>= FullDataSize
)
423 if (esl
->SignatureListSize
== 0 || esl
->SignatureSize
== 0)
426 dprint(L
"esl[%lu] 0x%llx = {sls=0x%lx, ss=0x%lx} esd:0x%llx\n",
427 i
, esl
, esl
->SignatureListSize
, esl
->SignatureSize
, esd
);
430 SPrint(namen
, namelen
, L
"%s%lu", name
, i
);
431 namen
[namelen
-1] = 0;
434 for (j
= 0; j
< namelen
; j
++)
435 namen8
[j
] = (CHAR8
)(namen
[j
] & 0xff);
436 namen8
[namelen
- 1] = 0;
440 * In case max_var_sz is computed dynamically, refresh the
443 efi_status
= get_max_var_sz(attrs
, &max_var_sz
);
444 if (EFI_ERROR(efi_status
)) {
445 LogError(L
"Could not get maximum variable size: %r",
454 /* The name counts towards the size of the variable */
455 max_var_sz
-= (StrLen(namen
) + 1) * 2;
456 dprint(L
"max_var_sz - name: %lx\n", max_var_sz
);
459 howmany
= MIN((max_var_sz
- sizeof(*esl
)) / esl
->SignatureSize
,
460 (esl_end_pos
- pos
) / esl
->SignatureSize
);
462 /* No signatures from this ESL can be mirrored in to a
463 * single variable, so skip it.
465 dprint(L
"skipping esl, pos:0x%llx->0x%llx\n", pos
, esl_end_pos
);
470 UINTN adj
= howmany
* esl
->SignatureSize
;
472 if (!only_first
&& i
== 0) {
473 dprint(L
"pos:0x%llx->0x%llx\n", pos
, pos
+ adj
);
480 efi_status
= mirror_one_esl(namen
, guid
, attrs
,
482 dprint(L
"esd:0x%llx adj:0x%llx\n", esd
, adj
);
483 if (EFI_ERROR(efi_status
)) {
484 LogError(L
"Could not mirror mok variable \"%s\": %r\n",
489 dprint(L
"pos:0x%llx->0x%llx\n", pos
, pos
+ adj
);
497 if (EFI_ERROR(efi_status
)) {
498 perror(L
"Failed to set %s: %r\n", name
, efi_status
);
499 } else if (only_first
&& !did_one
) {
501 * In this case we're going to try to create a
502 * dummy variable so that there's one there. It
503 * may or may not work, because on some firmware
504 * builds when the SetVariable call above fails it
505 * does actually set the variable(!), so aside from
506 * not using the allocation if it doesn't work, we
507 * don't care about failures here.
512 efi_status
= variable_create_esl_with_one_signature(
513 null_sha256
, sizeof(null_sha256
),
514 &EFI_CERT_SHA256_GUID
, &SHIM_LOCK_GUID
,
517 * from here we don't really care if it works or
520 if (!EFI_ERROR(efi_status
) && var
&& varsz
) {
521 efi_status
= SetVariable(name
, guid
,
522 EFI_VARIABLE_BOOTSERVICE_ACCESS
523 | EFI_VARIABLE_RUNTIME_ACCESS
,
532 static EFI_STATUS
NONNULL(1)
533 mirror_one_mok_variable(struct mok_state_variable
*v
,
536 EFI_STATUS efi_status
= EFI_SUCCESS
;
537 uint8_t *FullData
= NULL
;
538 size_t FullDataSize
= 0;
539 vendor_addend_category_t addend_category
= VENDOR_ADDEND_NONE
;
541 uint32_t attrs
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
542 EFI_VARIABLE_RUNTIME_ACCESS
;
543 BOOLEAN measure
= v
->flags
& MOK_VARIABLE_MEASURE
;
544 BOOLEAN log
= v
->flags
& MOK_VARIABLE_LOG
;
545 size_t build_cert_esl_sz
= 0, addend_esl_sz
= 0;
548 if (v
->categorize_addend
)
549 addend_category
= v
->categorize_addend(v
);
552 * if it is, there's more data
554 if (v
->flags
& MOK_MIRROR_KEYDB
) {
557 * We're mirroring (into) an efi security database, aka an
558 * array of EFI_SIGNATURE_LIST. Its layout goes like:
560 * existing_variable_data
561 * existing_variable_data_size
562 * if flags & MOK_MIRROR_KEYDB
565 * build_cert_header (always sz=0)
566 * build_cert_esd[0] { owner, data }
567 * if addend==vendor_db
570 * vendor_db_header_n (always sz=0)
571 * vendor_db_esd_n[m] {{ owner, data }, ... }
572 * elif addend==vendor_cert
574 * vendor_cert_header (always sz=0)
575 * vendor_cert_esd[1] { owner, data }
577 * first we determine the size of the variable, then alloc
582 * *first* vendor_db or vendor_cert
584 switch (addend_category
) {
585 case VENDOR_ADDEND_DB
:
587 * if it's an ESL already, we use it wholesale
589 FullDataSize
+= *v
->addend_size
;
590 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
591 FullDataSize
, FullData
);
593 case VENDOR_ADDEND_X509
:
594 efi_status
= fill_esl_with_one_signature(*v
->addend
,
596 &EFI_CERT_TYPE_X509_GUID
,
600 if (efi_status
!= EFI_BUFFER_TOO_SMALL
) {
601 perror(L
"Could not add built-in cert to %s: %r\n",
602 v
->name
, efi_status
);
605 FullDataSize
+= addend_esl_sz
;
606 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
607 FullDataSize
, FullData
);
610 case VENDOR_ADDEND_NONE
:
611 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
612 FullDataSize
, FullData
);
617 * then the build cert if it's there
619 if (should_mirror_build_cert(v
)) {
620 efi_status
= fill_esl_with_one_signature(*v
->build_cert
,
622 &EFI_CERT_TYPE_X509_GUID
,
624 NULL
, &build_cert_esl_sz
);
625 if (efi_status
!= EFI_BUFFER_TOO_SMALL
) {
626 perror(L
"Could not add built-in cert to %s: %r\n",
627 v
->name
, efi_status
);
630 FullDataSize
+= build_cert_esl_sz
;
631 dprint(L
"FullDataSize:0x%lx FullData:0x%llx\n",
632 FullDataSize
, FullData
);
638 * we're always mirroring the original data, whether this is an efi
639 * security database or not
641 dprint(L
"v->name:\"%s\" v->rtname:\"%s\"\n", v
->name
, v
->rtname
);
642 dprint(L
"v->data_size:%lu v->data:0x%llx\n", v
->data_size
, v
->data
);
643 dprint(L
"FullDataSize:%lu FullData:0x%llx\n", FullDataSize
, FullData
);
645 FullDataSize
+= v
->data_size
;
646 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
647 FullDataSize
, FullData
);
649 if (v
->data_size
== FullDataSize
)
653 * Now we have the full size
657 * allocate the buffer, or use the old one if it's just the
660 if (FullDataSize
== v
->data_size
) {
662 FullDataSize
= v
->data_size
;
663 p
= FullData
+ FullDataSize
;
664 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
665 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
669 dprint(L
"FullDataSize:%lu FullData:0x%llx allocating FullData\n",
670 FullDataSize
, FullData
);
672 * make sure we've got some zeroes at the end, just
677 allocsz
= FullDataSize
+ sizeof(EFI_SIGNATURE_LIST
);
678 new = ALIGN_VALUE(allocsz
, 4096);
679 allocsz
= new == allocsz
? new + 4096 : new;
680 FullData
= AllocateZeroPool(allocsz
);
682 perror(L
"Failed to allocate %lu bytes for %s\n",
683 FullDataSize
, v
->name
);
684 return EFI_OUT_OF_RESOURCES
;
689 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
690 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
695 if (v
->flags
& MOK_MIRROR_KEYDB
) {
697 * first vendor_cert or vendor_db
699 switch (addend_category
) {
700 case VENDOR_ADDEND_DB
:
701 CopyMem(p
, *v
->addend
, *v
->addend_size
);
702 p
+= *v
->addend_size
;
703 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
704 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
706 case VENDOR_ADDEND_X509
:
707 efi_status
= fill_esl_with_one_signature(*v
->addend
,
709 &EFI_CERT_TYPE_X509_GUID
,
712 if (EFI_ERROR(efi_status
)) {
713 perror(L
"Could not add built-in cert to %s: %r\n",
714 v
->name
, efi_status
);
718 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
719 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
722 case VENDOR_ADDEND_NONE
:
723 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
724 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
729 * then is the build cert
731 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
732 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
733 if (should_mirror_build_cert(v
)) {
734 efi_status
= fill_esl_with_one_signature(*v
->build_cert
,
736 &EFI_CERT_TYPE_X509_GUID
,
738 p
, &build_cert_esl_sz
);
739 if (EFI_ERROR(efi_status
)) {
740 perror(L
"Could not add built-in cert to %s: %r\n",
741 v
->name
, efi_status
);
744 p
+= build_cert_esl_sz
;
745 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
746 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
751 * last bit is existing data, unless it's the only thing,
752 * in which case it's already there.
755 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
756 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
757 if (v
->data
&& v
->data_size
) {
758 CopyMem(p
, v
->data
, v
->data_size
);
761 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
762 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
766 * We always want to create our key databases, so in this case we
769 if ((v
->flags
& MOK_MIRROR_KEYDB
) && FullDataSize
== 0) {
770 efi_status
= variable_create_esl_with_one_signature(
771 null_sha256
, sizeof(null_sha256
),
772 &EFI_CERT_SHA256_GUID
, &SHIM_LOCK_GUID
,
773 &FullData
, &FullDataSize
);
774 if (EFI_ERROR(efi_status
)) {
775 perror(L
"Failed to allocate %lu bytes for %s\n",
776 FullDataSize
, v
->name
);
779 p
= FullData
+ FullDataSize
;
780 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
781 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
784 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
785 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
786 if (FullDataSize
&& v
->flags
& MOK_MIRROR_KEYDB
) {
787 dprint(L
"calling mirror_mok_db(\"%s\", datasz=%lu)\n",
788 v
->rtname
, FullDataSize
);
789 efi_status
= mirror_mok_db(v
->rtname
, (CHAR8
*)v
->rtname8
, v
->guid
,
790 attrs
, FullData
, FullDataSize
,
792 dprint(L
"mirror_mok_db(\"%s\", datasz=%lu) returned %r\n",
793 v
->rtname
, FullDataSize
, efi_status
);
794 } else if (FullDataSize
&& only_first
) {
795 efi_status
= SetVariable(v
->rtname
, v
->guid
, attrs
,
796 FullDataSize
, FullData
);
798 if (FullDataSize
&& only_first
) {
801 * Measure this into PCR 7 in the Microsoft format
803 efi_status
= tpm_measure_variable(v
->name
, *v
->guid
,
804 FullDataSize
, FullData
);
805 if (EFI_ERROR(efi_status
)) {
806 dprint(L
"tpm_measure_variable(\"%s\",%lu,0x%llx)->%r\n",
807 v
->name
, FullDataSize
, FullData
, efi_status
);
814 * Log this variable into whichever PCR the table
817 EFI_PHYSICAL_ADDRESS datap
=
818 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FullData
,
819 efi_status
= tpm_log_event(datap
, FullDataSize
,
820 v
->pcr
, (CHAR8
*)v
->name8
);
821 if (EFI_ERROR(efi_status
)) {
822 dprint(L
"tpm_log_event(0x%llx, %lu, %lu, \"%s\")->%r\n",
823 FullData
, FullDataSize
, v
->pcr
, v
->name
,
830 if (v
->data
&& v
->data_size
&& v
->data
!= FullData
) {
836 v
->data_size
= FullDataSize
;
837 dprint(L
"returning %r\n", efi_status
);
842 * Mirror a variable if it has an rtname, and preserve any
843 * EFI_SECURITY_VIOLATION status at the same time.
845 static EFI_STATUS
NONNULL(1)
846 maybe_mirror_one_mok_variable(struct mok_state_variable
*v
,
847 EFI_STATUS ret
, BOOLEAN only_first
)
849 EFI_STATUS efi_status
;
850 BOOLEAN present
= FALSE
;
853 if (!only_first
&& (v
->flags
& MOK_MIRROR_DELETE_FIRST
)) {
854 dprint(L
"deleting \"%s\"\n", v
->rtname
);
855 efi_status
= LibDeleteVariable(v
->rtname
, v
->guid
);
856 dprint(L
"LibDeleteVariable(\"%s\",...) => %r\n", v
->rtname
, efi_status
);
859 efi_status
= mirror_one_mok_variable(v
, only_first
);
860 if (EFI_ERROR(efi_status
)) {
861 if (ret
!= EFI_SECURITY_VIOLATION
)
863 perror(L
"Could not create %s: %r\n", v
->rtname
,
868 present
= (v
->data
&& v
->data_size
) ? TRUE
: FALSE
;
872 if (v
->data_size
== sizeof(UINT8
) && v
->state
) {
873 *v
->state
= v
->data
[0];
879 struct mok_variable_config_entry
{
885 EFI_STATUS
import_one_mok_state(struct mok_state_variable
*v
,
888 EFI_STATUS ret
= EFI_SUCCESS
;
889 EFI_STATUS efi_status
;
891 user_insecure_mode
= 0;
895 BOOLEAN
delete = FALSE
;
897 dprint(L
"importing mok state for \"%s\"\n", v
->name
);
899 efi_status
= get_variable_attr(v
->name
,
900 &v
->data
, &v
->data_size
,
902 if (efi_status
== EFI_NOT_FOUND
) {
905 } else if (EFI_ERROR(efi_status
)) {
906 perror(L
"Could not verify %s: %r\n", v
->name
,
910 if (!(attrs
& v
->yes_attr
)) {
911 perror(L
"Variable %s is missing attributes:\n",
913 perror(L
" 0x%08x should have 0x%08x set.\n",
917 if (attrs
& v
->no_attr
) {
918 perror(L
"Variable %s has incorrect attribute:\n",
920 perror(L
" 0x%08x should not have 0x%08x set.\n",
925 if (delete == TRUE
) {
926 perror(L
"Deleting bad variable %s\n", v
->name
);
927 efi_status
= LibDeleteVariable(v
->name
, v
->guid
);
928 if (EFI_ERROR(efi_status
)) {
929 perror(L
"Failed to erase %s\n", v
->name
);
930 ret
= EFI_SECURITY_VIOLATION
;
937 dprint(L
"maybe mirroring \"%s\". original data:\n", v
->name
);
938 dhexdumpat(v
->data
, v
->data_size
, 0);
940 ret
= maybe_mirror_one_mok_variable(v
, ret
, only_first
);
941 dprint(L
"returning %r\n", ret
);
946 * Verify our non-volatile MoK state. This checks the variables above
947 * accessable and have valid attributes. If they don't, it removes
948 * them. If any of them can't be removed, our ability to do this is
949 * comprimized, so return EFI_SECURITY_VIOLATION.
951 * Any variable that isn't deleted and has ->measure == TRUE is then
952 * measured into the tpm.
954 * Any variable with a ->rtname element is then mirrored to a
955 * runtime-accessable version. The new ones won't be marked NV, so the OS
958 EFI_STATUS
import_mok_state(EFI_HANDLE image_handle
)
961 EFI_STATUS ret
= EFI_SUCCESS
;
962 EFI_STATUS efi_status
;
964 user_insecure_mode
= 0;
967 UINT64 config_sz
= 0;
968 UINT8
*config_table
= NULL
;
970 struct mok_variable_config_entry config_template
;
972 dprint(L
"importing minimal mok state variables\n");
973 for (i
= 0; mok_state_variables
[i
].name
!= NULL
; i
++) {
974 struct mok_state_variable
*v
= &mok_state_variables
[i
];
976 efi_status
= import_one_mok_state(v
, TRUE
);
977 if (EFI_ERROR(efi_status
)) {
978 dprint(L
"import_one_mok_state(ih, \"%s\", TRUE): %r\n",
981 * don't clobber EFI_SECURITY_VIOLATION from some
982 * other variable in the list.
984 if (ret
!= EFI_SECURITY_VIOLATION
)
988 if (v
->data
&& v
->data_size
) {
989 config_sz
+= v
->data_size
;
990 config_sz
+= sizeof(config_template
);
995 * Alright, so we're going to copy these to a config table. The
996 * table is a packed array of N+1 struct mok_variable_config_entry
997 * items, with the last item having all zero's in name and
1001 config_sz
+= sizeof(config_template
);
1002 npages
= ALIGN_VALUE(config_sz
, PAGE_SIZE
) >> EFI_PAGE_SHIFT
;
1003 config_table
= NULL
;
1004 efi_status
= gBS
->AllocatePages(AllocateAnyPages
,
1005 EfiRuntimeServicesData
,
1007 (EFI_PHYSICAL_ADDRESS
*)&config_table
);
1008 if (EFI_ERROR(efi_status
) || !config_table
) {
1009 console_print(L
"Allocating %lu pages for mok config table failed: %r\n",
1010 npages
, efi_status
);
1011 config_table
= NULL
;
1013 ZeroMem(config_table
, npages
<< EFI_PAGE_SHIFT
);
1017 UINT8
*p
= (UINT8
*)config_table
;
1018 for (i
= 0; p
&& mok_state_variables
[i
].name
!= NULL
; i
++) {
1019 struct mok_state_variable
*v
= &mok_state_variables
[i
];
1021 ZeroMem(&config_template
, sizeof(config_template
));
1022 strncpy(config_template
.name
, (CHAR8
*)v
->rtname8
, 255);
1023 config_template
.name
[255] = '\0';
1025 config_template
.data_size
= v
->data_size
;
1027 CopyMem(p
, &config_template
, sizeof(config_template
));
1028 p
+= sizeof(config_template
);
1029 CopyMem(p
, v
->data
, v
->data_size
);
1033 ZeroMem(&config_template
, sizeof(config_template
));
1034 CopyMem(p
, &config_template
, sizeof(config_template
));
1036 efi_status
= gBS
->InstallConfigurationTable(&MOK_VARIABLE_STORE
,
1038 if (EFI_ERROR(efi_status
)) {
1039 console_print(L
"Couldn't install MoK configuration table\n");
1044 * This is really just to make it easy for userland.
1046 dprint(L
"importing full mok state variables\n");
1047 for (i
= 0; mok_state_variables
[i
].name
!= NULL
; i
++) {
1048 struct mok_state_variable
*v
= &mok_state_variables
[i
];
1050 import_one_mok_state(v
, FALSE
);
1054 * Enter MokManager if necessary. Any actual *changes* here will
1055 * cause MokManager to demand a machine reboot, so this is safe to
1056 * have after the entire loop.
1058 dprint(L
"checking mok request\n");
1059 efi_status
= check_mok_request(image_handle
);
1060 dprint(L
"mok returned %r\n", efi_status
);
1061 if (EFI_ERROR(efi_status
)) {
1063 * don't clobber EFI_SECURITY_VIOLATION
1065 if (ret
!= EFI_SECURITY_VIOLATION
)
1070 dprint(L
"returning %r\n", ret
);
1074 // vim:fenc=utf-8:tw=75:noet