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
= RT
->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_ = RT->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") || check_var(L
"MokListTrustedNew")) {
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
);
61 static vendor_addend_category_t
62 categorize_authorized(struct mok_state_variable
*v
)
64 if (!(v
->addend
&& v
->addend_size
&&
65 *v
->addend
&& *v
->addend_size
)) {
66 return VENDOR_ADDEND_NONE
;
69 return vendor_authorized_category
;
72 static vendor_addend_category_t
73 categorize_deauthorized(struct mok_state_variable
*v
)
75 if (!(v
->addend
&& v
->addend_size
&&
76 *v
->addend
&& *v
->addend_size
)) {
77 return VENDOR_ADDEND_NONE
;
80 return VENDOR_ADDEND_DB
;
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 #define MOK_VARIABLE_INVERSE 0x10
89 struct mok_state_variable mok_state_variable_data
[] = {
92 .rtname
= L
"MokListRT",
93 .rtname8
= "MokListRT",
94 .guid
= &SHIM_LOCK_GUID
,
95 .yes_attr
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
96 EFI_VARIABLE_NON_VOLATILE
,
97 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
98 .categorize_addend
= categorize_authorized
,
99 .addend
= &vendor_authorized
,
100 .addend_size
= &vendor_authorized_size
,
101 .user_cert
= &user_cert
,
102 .user_cert_size
= &user_cert_size
,
103 #if defined(ENABLE_SHIM_CERT)
104 .build_cert
= &build_cert
,
105 .build_cert_size
= &build_cert_size
,
106 #endif /* defined(ENABLE_SHIM_CERT) */
107 .flags
= MOK_MIRROR_KEYDB
|
108 MOK_MIRROR_DELETE_FIRST
|
112 {.name
= L
"MokListX",
114 .rtname
= L
"MokListXRT",
115 .rtname8
= "MokListXRT",
116 .guid
= &SHIM_LOCK_GUID
,
117 .yes_attr
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
118 EFI_VARIABLE_NON_VOLATILE
,
119 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
120 .categorize_addend
= categorize_deauthorized
,
121 .addend
= &vendor_deauthorized
,
122 .addend_size
= &vendor_deauthorized_size
,
123 .flags
= MOK_MIRROR_KEYDB
|
124 MOK_MIRROR_DELETE_FIRST
|
128 {.name
= L
"MokSBState",
129 .name8
= "MokSBState",
130 .rtname
= L
"MokSBStateRT",
131 .rtname8
= "MokSBStateRT",
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
|
140 .state
= &user_insecure_mode
,
142 {.name
= L
"MokDBState",
143 .name8
= "MokDBState",
144 .rtname
= L
"MokIgnoreDB",
145 .rtname8
= "MokIgnoreDB",
146 .guid
= &SHIM_LOCK_GUID
,
147 .yes_attr
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
148 EFI_VARIABLE_NON_VOLATILE
,
149 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
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
,
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.
163 #if !defined(ENABLE_SHIM_DEVEL)
164 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
168 .flags
= MOK_MIRROR_DELETE_FIRST
|
169 MOK_VARIABLE_MEASURE
,
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
|
181 MOK_VARIABLE_MEASURE
|
182 MOK_VARIABLE_INVERSE
|
185 .state
= &trust_mok_list
,
187 {.name
= L
"MokPolicy",
188 .name8
= "MokPolicy",
189 .rtname
= L
"MokPolicyRT",
190 .rtname8
= "MokPolicyRT",
191 .guid
= &SHIM_LOCK_GUID
,
192 .yes_attr
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
193 EFI_VARIABLE_NON_VOLATILE
,
194 .no_attr
= EFI_VARIABLE_RUNTIME_ACCESS
,
195 .flags
= MOK_MIRROR_DELETE_FIRST
|
198 .state
= &mok_policy
,
202 size_t n_mok_state_variables
= sizeof(mok_state_variable_data
) / sizeof(mok_state_variable_data
[0]);
203 struct mok_state_variable
*mok_state_variables
= &mok_state_variable_data
[0];
205 #define should_mirror_addend(v) (((v)->categorize_addend) && ((v)->categorize_addend(v) != VENDOR_ADDEND_NONE))
207 static inline BOOLEAN
NONNULL(1)
208 should_mirror_build_cert(struct mok_state_variable
*v
)
210 return (v
->build_cert
&& v
->build_cert_size
&&
211 *v
->build_cert
&& *v
->build_cert_size
) ? TRUE
: FALSE
;
214 static const uint8_t null_sha256
[32] = { 0, };
216 typedef UINTN SIZE_T
;
218 #define EFI_MAJOR_VERSION(tablep) ((UINT16)((((tablep)->Hdr.Revision) >> 16) & 0xfffful))
219 #define EFI_MINOR_VERSION(tablep) ((UINT16)(((tablep)->Hdr.Revision) & 0xfffful))
222 get_max_var_sz(UINT32 attrs
, SIZE_T
*max_var_szp
)
224 EFI_STATUS efi_status
;
225 uint64_t max_storage_sz
= 0;
226 uint64_t remaining_sz
= 0;
227 uint64_t max_var_sz
= 0;
230 if (EFI_MAJOR_VERSION(RT
) < 2) {
231 dprint(L
"EFI %d.%d; no RT->QueryVariableInfo(). Using 1024!\n",
232 EFI_MAJOR_VERSION(RT
), EFI_MINOR_VERSION(RT
));
233 max_var_sz
= remaining_sz
= max_storage_sz
= 1024;
234 efi_status
= EFI_SUCCESS
;
236 dprint(L
"calling RT->QueryVariableInfo() at 0x%lx\n",
237 RT
->QueryVariableInfo
);
238 efi_status
= RT
->QueryVariableInfo(attrs
, &max_storage_sz
,
239 &remaining_sz
, &max_var_sz
);
240 if (EFI_ERROR(efi_status
)) {
241 perror(L
"Could not get variable storage info: %r\n",
248 * I just don't trust implementations to not be showing static data
251 *max_var_szp
= (max_var_sz
< remaining_sz
) ? max_var_sz
: remaining_sz
;
252 dprint("max_var_sz:%lx remaining_sz:%lx max_storage_sz:%lx\n",
253 max_var_sz
, remaining_sz
, max_storage_sz
);
258 * If any entries fit in < maxsz, and nothing goes wrong, create a variable
259 * of the given name and guid with as many esd entries as possible in it,
260 * and updates *esdp with what would be the next entry (even if makes *esdp
261 * > esl+esl->SignatureListSize), and returns whatever SetVariable()
264 * If no entries fit (i.e. sizeof(esl) + esl->SignatureSize > maxsz),
265 * returns EFI_BUFFER_TOO_SMALL;
268 mirror_one_esl(CHAR16
*name
, EFI_GUID
*guid
, UINT32 attrs
,
269 EFI_SIGNATURE_LIST
*esl
, EFI_SIGNATURE_DATA
*esd
,
272 EFI_STATUS efi_status
;
277 * We always assume esl->SignatureHeaderSize is 0 (and so far,
278 * that's true as per UEFI 2.8)
280 dprint(L
"Trying to add %lx signatures to \"%s\" of size %lx\n",
281 howmany
, name
, esl
->SignatureSize
);
284 * Because of the semantics of variable_create_esl(), the first
285 * owner guid from the data is not part of esdsz, or the data.
289 efi_status
= variable_create_esl(esd
, howmany
,
293 if (EFI_ERROR(efi_status
) || !var
|| !varsz
) {
294 LogError(L
"Couldn't allocate %lu bytes for mok variable \"%s\": %r\n",
295 varsz
, var
, efi_status
);
299 dprint(L
"new esl:\n");
300 dhexdumpat(var
, varsz
, 0);
302 efi_status
= SetVariable(name
, guid
, attrs
, varsz
, var
);
304 if (EFI_ERROR(efi_status
)) {
305 LogError(L
"Couldn't create mok variable \"%s\": %r\n",
306 varsz
, var
, efi_status
);
314 mirror_mok_db(CHAR16
*name
, CHAR8
*name8
, EFI_GUID
*guid
, UINT32 attrs
,
315 UINT8
*FullData
, SIZE_T FullDataSize
, BOOLEAN only_first
)
317 EFI_STATUS efi_status
= EFI_SUCCESS
;
320 efi_status
= get_max_var_sz(attrs
, &max_var_sz
);
321 if (EFI_ERROR(efi_status
) && efi_status
!= EFI_UNSUPPORTED
) {
322 LogError(L
"Could not get maximum variable size: %r",
327 /* Some UEFI environment such as u-boot doesn't implement
328 * QueryVariableInfo() and we will only get EFI_UNSUPPORTED when
329 * querying the available space. In this case, we just mirror
330 * the variable directly. */
331 if (FullDataSize
<= max_var_sz
|| efi_status
== EFI_UNSUPPORTED
) {
332 efi_status
= EFI_SUCCESS
;
334 efi_status
= SetVariable(name
, guid
, attrs
,
335 FullDataSize
, FullData
);
342 UINTN namelen
, namesz
;
344 namelen
= StrLen(name
);
345 namesz
= namelen
* 2;
352 namen
= AllocateZeroPool(namesz
);
354 LogError(L
"Could not allocate %lu bytes", namesz
);
355 return EFI_OUT_OF_RESOURCES
;
357 namen8
= AllocateZeroPool(namelen
);
360 LogError(L
"Could not allocate %lu bytes", namelen
);
361 return EFI_OUT_OF_RESOURCES
;
366 const SIZE_T minsz
= sizeof(EFI_SIGNATURE_LIST
)
367 + sizeof(EFI_SIGNATURE_DATA
)
369 BOOLEAN did_one
= FALSE
;
372 * Create any entries that can fit.
375 dprint(L
"full data for \"%s\":\n", name
);
376 dhexdumpat(FullData
, FullDataSize
, 0);
378 EFI_SIGNATURE_LIST
*esl
= NULL
;
379 UINTN esl_end_pos
= 0;
380 for (i
= 0, pos
= 0; FullDataSize
- pos
>= minsz
&& FullData
; ) {
381 EFI_SIGNATURE_DATA
*esd
= NULL
;
383 dprint(L
"pos:0x%llx FullDataSize:0x%llx\n", pos
, FullDataSize
);
384 if (esl
== NULL
|| pos
>= esl_end_pos
) {
385 UINT8
*nesl
= FullData
+ pos
;
386 dprint(L
"esl:0x%llx->0x%llx\n", esl
, nesl
);
387 esl
= (EFI_SIGNATURE_LIST
*)nesl
;
388 esl_end_pos
= pos
+ esl
->SignatureListSize
;
389 dprint(L
"pos:0x%llx->0x%llx\n", pos
, pos
+ sizeof(*esl
));
392 esd
= (EFI_SIGNATURE_DATA
*)(FullData
+ pos
);
393 if (pos
>= FullDataSize
)
395 if (esl
->SignatureListSize
== 0 || esl
->SignatureSize
== 0)
398 dprint(L
"esl[%lu] 0x%llx = {sls=0x%lx, ss=0x%lx} esd:0x%llx\n",
399 i
, esl
, esl
->SignatureListSize
, esl
->SignatureSize
, esd
);
402 SPrint(namen
, namelen
, L
"%s%lu", name
, i
);
403 namen
[namelen
-1] = 0;
406 for (j
= 0; j
< namelen
; j
++)
407 namen8
[j
] = (CHAR8
)(namen
[j
] & 0xff);
408 namen8
[namelen
- 1] = 0;
412 * In case max_var_sz is computed dynamically, refresh the
415 efi_status
= get_max_var_sz(attrs
, &max_var_sz
);
416 if (EFI_ERROR(efi_status
)) {
417 LogError(L
"Could not get maximum variable size: %r",
426 /* The name counts towards the size of the variable */
427 max_var_sz
-= (StrLen(namen
) + 1) * 2;
428 dprint(L
"max_var_sz - name: %lx\n", max_var_sz
);
431 howmany
= MIN((max_var_sz
- sizeof(*esl
)) / esl
->SignatureSize
,
432 (esl_end_pos
- pos
) / esl
->SignatureSize
);
434 /* No signatures from this ESL can be mirrored in to a
435 * single variable, so skip it.
437 dprint(L
"skipping esl, pos:0x%llx->0x%llx\n", pos
, esl_end_pos
);
442 UINTN adj
= howmany
* esl
->SignatureSize
;
444 if (!only_first
&& i
== 0) {
445 dprint(L
"pos:0x%llx->0x%llx\n", pos
, pos
+ adj
);
452 efi_status
= mirror_one_esl(namen
, guid
, attrs
,
454 dprint(L
"esd:0x%llx adj:0x%llx\n", esd
, adj
);
455 if (EFI_ERROR(efi_status
)) {
456 LogError(L
"Could not mirror mok variable \"%s\": %r\n",
461 dprint(L
"pos:0x%llx->0x%llx\n", pos
, pos
+ adj
);
469 if (EFI_ERROR(efi_status
)) {
470 perror(L
"Failed to set %s: %r\n", name
, efi_status
);
471 } else if (only_first
&& !did_one
) {
473 * In this case we're going to try to create a
474 * dummy variable so that there's one there. It
475 * may or may not work, because on some firmware
476 * builds when the SetVariable call above fails it
477 * does actually set the variable(!), so aside from
478 * not using the allocation if it doesn't work, we
479 * don't care about failures here.
484 efi_status
= variable_create_esl_with_one_signature(
485 null_sha256
, sizeof(null_sha256
),
486 &EFI_CERT_SHA256_GUID
, &SHIM_LOCK_GUID
,
489 * from here we don't really care if it works or
492 if (!EFI_ERROR(efi_status
) && var
&& varsz
) {
493 efi_status
= SetVariable(name
, guid
,
494 EFI_VARIABLE_BOOTSERVICE_ACCESS
495 | EFI_VARIABLE_RUNTIME_ACCESS
,
504 static EFI_STATUS
NONNULL(1)
505 mirror_one_mok_variable(struct mok_state_variable
*v
,
508 EFI_STATUS efi_status
= EFI_SUCCESS
;
509 uint8_t *FullData
= NULL
;
510 size_t FullDataSize
= 0;
511 vendor_addend_category_t addend_category
= VENDOR_ADDEND_NONE
;
513 uint32_t attrs
= EFI_VARIABLE_BOOTSERVICE_ACCESS
|
514 EFI_VARIABLE_RUNTIME_ACCESS
;
515 BOOLEAN measure
= v
->flags
& MOK_VARIABLE_MEASURE
;
516 BOOLEAN log
= v
->flags
& MOK_VARIABLE_LOG
;
517 size_t build_cert_esl_sz
= 0, addend_esl_sz
= 0;
520 if (v
->categorize_addend
)
521 addend_category
= v
->categorize_addend(v
);
524 * if it is, there's more data
526 if (v
->flags
& MOK_MIRROR_KEYDB
) {
529 * We're mirroring (into) an efi security database, aka an
530 * array of EFI_SIGNATURE_LIST. Its layout goes like:
532 * existing_variable_data
533 * existing_variable_data_size
534 * if flags & MOK_MIRROR_KEYDB
537 * build_cert_header (always sz=0)
538 * build_cert_esd[0] { owner, data }
539 * if addend==vendor_db
542 * vendor_db_header_n (always sz=0)
543 * vendor_db_esd_n[m] {{ owner, data }, ... }
544 * elif addend==vendor_cert
546 * vendor_cert_header (always sz=0)
547 * vendor_cert_esd[1] { owner, data }
549 * first we determine the size of the variable, then alloc
554 * *first* vendor_db or vendor_cert
556 switch (addend_category
) {
557 case VENDOR_ADDEND_DB
:
559 * if it's an ESL already, we use it wholesale
561 FullDataSize
+= *v
->addend_size
;
562 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
563 FullDataSize
, FullData
);
565 case VENDOR_ADDEND_X509
:
566 efi_status
= fill_esl_with_one_signature(*v
->addend
,
568 &EFI_CERT_TYPE_X509_GUID
,
572 if (efi_status
!= EFI_BUFFER_TOO_SMALL
) {
573 perror(L
"Could not add built-in cert to %s: %r\n",
574 v
->name
, efi_status
);
577 FullDataSize
+= addend_esl_sz
;
578 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
579 FullDataSize
, FullData
);
582 case VENDOR_ADDEND_NONE
:
583 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
584 FullDataSize
, FullData
);
589 * then the build cert if it's there
591 if (should_mirror_build_cert(v
)) {
592 efi_status
= fill_esl_with_one_signature(*v
->build_cert
,
594 &EFI_CERT_TYPE_X509_GUID
,
596 NULL
, &build_cert_esl_sz
);
597 if (efi_status
!= EFI_BUFFER_TOO_SMALL
) {
598 perror(L
"Could not add built-in cert to %s: %r\n",
599 v
->name
, efi_status
);
602 FullDataSize
+= build_cert_esl_sz
;
603 dprint(L
"FullDataSize:0x%lx FullData:0x%llx\n",
604 FullDataSize
, FullData
);
606 if (v
->user_cert_size
)
607 FullDataSize
+= *v
->user_cert_size
;
611 * we're always mirroring the original data, whether this is an efi
612 * security database or not
614 dprint(L
"v->name:\"%s\" v->rtname:\"%s\"\n", v
->name
, v
->rtname
);
615 dprint(L
"v->data_size:%lu v->data:0x%llx\n", v
->data_size
, v
->data
);
616 dprint(L
"FullDataSize:%lu FullData:0x%llx\n", FullDataSize
, FullData
);
618 FullDataSize
+= v
->data_size
;
619 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
620 FullDataSize
, FullData
);
622 if (v
->data_size
== FullDataSize
)
626 * Now we have the full size
630 * allocate the buffer, or use the old one if it's just the
633 if (FullDataSize
== v
->data_size
) {
635 FullDataSize
= v
->data_size
;
636 p
= FullData
+ FullDataSize
;
637 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
638 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
642 dprint(L
"FullDataSize:%lu FullData:0x%llx allocating FullData\n",
643 FullDataSize
, FullData
);
645 * make sure we've got some zeroes at the end, just
650 allocsz
= FullDataSize
+ sizeof(EFI_SIGNATURE_LIST
);
651 new = ALIGN_VALUE(allocsz
, 4096);
652 allocsz
= new == allocsz
? new + 4096 : new;
653 FullData
= AllocateZeroPool(allocsz
);
655 perror(L
"Failed to allocate %lu bytes for %s\n",
656 FullDataSize
, v
->name
);
657 return EFI_OUT_OF_RESOURCES
;
662 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
663 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
668 if (v
->flags
& MOK_MIRROR_KEYDB
) {
670 * first vendor_cert or vendor_db
672 switch (addend_category
) {
673 case VENDOR_ADDEND_DB
:
674 CopyMem(p
, *v
->addend
, *v
->addend_size
);
675 p
+= *v
->addend_size
;
676 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
677 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
679 case VENDOR_ADDEND_X509
:
680 efi_status
= fill_esl_with_one_signature(*v
->addend
,
682 &EFI_CERT_TYPE_X509_GUID
,
685 if (EFI_ERROR(efi_status
)) {
686 perror(L
"Could not add built-in cert to %s: %r\n",
687 v
->name
, efi_status
);
691 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
692 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
695 case VENDOR_ADDEND_NONE
:
696 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
697 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
702 * then is the build cert
704 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
705 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
706 if (should_mirror_build_cert(v
)) {
707 efi_status
= fill_esl_with_one_signature(*v
->build_cert
,
709 &EFI_CERT_TYPE_X509_GUID
,
711 p
, &build_cert_esl_sz
);
712 if (EFI_ERROR(efi_status
)) {
713 perror(L
"Could not add built-in cert to %s: %r\n",
714 v
->name
, efi_status
);
717 p
+= build_cert_esl_sz
;
718 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
719 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
721 if (v
->user_cert_size
) {
722 CopyMem(p
, *v
->user_cert
, *v
->user_cert_size
);
723 p
+= *v
->user_cert_size
;
728 * last bit is existing data, unless it's the only thing,
729 * in which case it's already there.
732 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
733 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
734 if (v
->data
&& v
->data_size
) {
735 CopyMem(p
, v
->data
, v
->data_size
);
738 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
739 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
743 * We always want to create our key databases, so in this case we
746 if ((v
->flags
& MOK_MIRROR_KEYDB
) && FullDataSize
== 0) {
747 efi_status
= variable_create_esl_with_one_signature(
748 null_sha256
, sizeof(null_sha256
),
749 &EFI_CERT_SHA256_GUID
, &SHIM_LOCK_GUID
,
750 &FullData
, &FullDataSize
);
751 if (EFI_ERROR(efi_status
)) {
752 perror(L
"Failed to allocate %lu bytes for %s\n",
753 FullDataSize
, v
->name
);
756 p
= FullData
+ FullDataSize
;
757 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
758 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
761 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
762 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
763 if (FullDataSize
&& v
->flags
& MOK_MIRROR_KEYDB
) {
764 dprint(L
"calling mirror_mok_db(\"%s\", datasz=%lu)\n",
765 v
->rtname
, FullDataSize
);
766 efi_status
= mirror_mok_db(v
->rtname
, (CHAR8
*)v
->rtname8
, v
->guid
,
767 attrs
, FullData
, FullDataSize
,
769 dprint(L
"mirror_mok_db(\"%s\", datasz=%lu) returned %r\n",
770 v
->rtname
, FullDataSize
, efi_status
);
771 } else if (FullDataSize
&& only_first
) {
772 efi_status
= SetVariable(v
->rtname
, v
->guid
, attrs
,
773 FullDataSize
, FullData
);
775 if (FullDataSize
&& only_first
) {
778 * Measure this into PCR 7 in the Microsoft format
780 efi_status
= tpm_measure_variable(v
->name
, *v
->guid
,
781 FullDataSize
, FullData
);
782 if (EFI_ERROR(efi_status
)) {
783 dprint(L
"tpm_measure_variable(\"%s\",%lu,0x%llx)->%r\n",
784 v
->name
, FullDataSize
, FullData
, efi_status
);
791 * Log this variable into whichever PCR the table
794 EFI_PHYSICAL_ADDRESS datap
=
795 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FullData
,
796 efi_status
= tpm_log_event(datap
, FullDataSize
,
797 v
->pcr
, (CHAR8
*)v
->name8
);
798 if (EFI_ERROR(efi_status
)) {
799 dprint(L
"tpm_log_event(0x%llx, %lu, %lu, \"%s\")->%r\n",
800 FullData
, FullDataSize
, v
->pcr
, v
->name
,
807 if (v
->data
&& v
->data_size
&& v
->data
!= FullData
) {
813 v
->data_size
= FullDataSize
;
814 dprint(L
"returning %r\n", efi_status
);
819 * Mirror a variable if it has an rtname, and preserve any
820 * EFI_SECURITY_VIOLATION status at the same time.
822 static EFI_STATUS
NONNULL(1)
823 maybe_mirror_one_mok_variable(struct mok_state_variable
*v
,
824 EFI_STATUS ret
, BOOLEAN only_first
)
826 EFI_STATUS efi_status
;
827 BOOLEAN present
= FALSE
;
830 if (only_first
&& (v
->flags
& MOK_MIRROR_DELETE_FIRST
)) {
831 dprint(L
"deleting \"%s\"\n", v
->rtname
);
832 efi_status
= LibDeleteVariable(v
->rtname
, v
->guid
);
833 dprint(L
"LibDeleteVariable(\"%s\",...) => %r\n", v
->rtname
, efi_status
);
836 efi_status
= mirror_one_mok_variable(v
, only_first
);
837 if (EFI_ERROR(efi_status
)) {
838 if (ret
!= EFI_SECURITY_VIOLATION
)
840 perror(L
"Could not create %s: %r\n", v
->rtname
,
845 present
= (v
->data
&& v
->data_size
) ? TRUE
: FALSE
;
849 if (v
->data_size
== sizeof(UINT8
) && v
->state
) {
850 *v
->state
= v
->data
[0];
856 EFI_STATUS
import_one_mok_state(struct mok_state_variable
*v
,
859 EFI_STATUS ret
= EFI_SUCCESS
;
860 EFI_STATUS efi_status
;
863 BOOLEAN
delete = FALSE
;
865 dprint(L
"importing mok state for \"%s\"\n", v
->name
);
867 if (!v
->data
&& !v
->data_size
) {
868 efi_status
= get_variable_attr(v
->name
,
869 &v
->data
, &v
->data_size
,
871 if (efi_status
== EFI_NOT_FOUND
&&
872 v
->flags
& MOK_VARIABLE_INVERSE
) {
873 v
->data
= AllocateZeroPool(4);
875 perror(L
"Out of memory\n");
876 return EFI_OUT_OF_RESOURCES
;
880 } else if (efi_status
== EFI_NOT_FOUND
) {
883 } else if (EFI_ERROR(efi_status
)) {
884 perror(L
"Could not verify %s: %r\n", v
->name
,
888 if (!(attrs
& v
->yes_attr
)) {
889 perror(L
"Variable %s is missing attributes:\n",
891 perror(L
" 0x%08x should have 0x%08x set.\n",
895 if (attrs
& v
->no_attr
) {
896 perror(L
"Variable %s has incorrect attribute:\n",
898 perror(L
" 0x%08x should not have 0x%08x set.\n",
902 if (v
->flags
& MOK_VARIABLE_INVERSE
) {
909 if (delete == TRUE
) {
910 perror(L
"Deleting bad variable %s\n", v
->name
);
911 efi_status
= LibDeleteVariable(v
->name
, v
->guid
);
912 if (EFI_ERROR(efi_status
)) {
913 perror(L
"Failed to erase %s\n", v
->name
);
914 ret
= EFI_SECURITY_VIOLATION
;
921 dprint(L
"maybe mirroring \"%s\". original data:\n", v
->name
);
922 if (v
->data
&& v
->data_size
) {
923 dhexdumpat(v
->data
, v
->data_size
, 0);
926 ret
= maybe_mirror_one_mok_variable(v
, ret
, only_first
);
927 dprint(L
"returning %r\n", ret
);
932 * Verify our non-volatile MoK state. This checks the variables above
933 * accessable and have valid attributes. If they don't, it removes
934 * them. If any of them can't be removed, our ability to do this is
935 * comprimized, so return EFI_SECURITY_VIOLATION.
937 * Any variable that isn't deleted and has ->measure == TRUE is then
938 * measured into the tpm.
940 * Any variable with a ->rtname element is then mirrored to a
941 * runtime-accessable version. The new ones won't be marked NV, so the OS
944 EFI_STATUS
import_mok_state(EFI_HANDLE image_handle
)
947 EFI_STATUS ret
= EFI_SUCCESS
;
948 EFI_STATUS efi_status
;
950 user_insecure_mode
= 0;
954 UINT64 config_sz
= 0;
955 UINT8
*config_table
= NULL
;
957 struct mok_variable_config_entry config_template
;
959 dprint(L
"importing minimal mok state variables\n");
960 for (i
= 0; mok_state_variables
[i
].name
!= NULL
; i
++) {
961 struct mok_state_variable
*v
= &mok_state_variables
[i
];
963 efi_status
= import_one_mok_state(v
, TRUE
);
964 if (EFI_ERROR(efi_status
)) {
965 dprint(L
"import_one_mok_state(ih, \"%s\", TRUE): %r\n",
968 * don't clobber EFI_SECURITY_VIOLATION from some
969 * other variable in the list.
971 if (ret
!= EFI_SECURITY_VIOLATION
)
975 if (v
->data
&& v
->data_size
) {
976 config_sz
+= v
->data_size
;
977 config_sz
+= sizeof(config_template
);
982 * Alright, so we're going to copy these to a config table. The
983 * table is a packed array of N+1 struct mok_variable_config_entry
984 * items, with the last item having all zero's in name and
988 config_sz
+= sizeof(config_template
);
989 npages
= ALIGN_VALUE(config_sz
, PAGE_SIZE
) >> EFI_PAGE_SHIFT
;
991 efi_status
= BS
->AllocatePages(
992 AllocateAnyPages
, EfiRuntimeServicesData
, npages
,
993 (EFI_PHYSICAL_ADDRESS
*)&config_table
);
994 if (EFI_ERROR(efi_status
) || !config_table
) {
995 console_print(L
"Allocating %lu pages for mok config table failed: %r\n",
999 ZeroMem(config_table
, npages
<< EFI_PAGE_SHIFT
);
1003 UINT8
*p
= (UINT8
*)config_table
;
1004 for (i
= 0; p
&& mok_state_variables
[i
].name
!= NULL
; i
++) {
1005 struct mok_state_variable
*v
= &mok_state_variables
[i
];
1007 ZeroMem(&config_template
, sizeof(config_template
));
1008 strncpy(config_template
.name
, (CHAR8
*)v
->rtname8
, 255);
1009 config_template
.name
[255] = '\0';
1011 config_template
.data_size
= v
->data_size
;
1013 if (v
->data
&& v
->data_size
) {
1014 CopyMem(p
, &config_template
, sizeof(config_template
));
1015 p
+= sizeof(config_template
);
1016 CopyMem(p
, v
->data
, v
->data_size
);
1021 ZeroMem(&config_template
, sizeof(config_template
));
1022 CopyMem(p
, &config_template
, sizeof(config_template
));
1024 efi_status
= BS
->InstallConfigurationTable(&MOK_VARIABLE_STORE
,
1026 if (EFI_ERROR(efi_status
)) {
1027 console_print(L
"Couldn't install MoK configuration table\n");
1032 * This is really just to make it easy for userland.
1034 dprint(L
"importing full mok state variables\n");
1035 for (i
= 0; mok_state_variables
[i
].name
!= NULL
; i
++) {
1036 struct mok_state_variable
*v
= &mok_state_variables
[i
];
1038 import_one_mok_state(v
, FALSE
);
1042 * Enter MokManager if necessary. Any actual *changes* here will
1043 * cause MokManager to demand a machine reboot, so this is safe to
1044 * have after the entire loop.
1046 dprint(L
"checking mok request\n");
1047 efi_status
= check_mok_request(image_handle
);
1048 dprint(L
"mok returned %r\n", efi_status
);
1049 if (EFI_ERROR(efi_status
)) {
1051 * don't clobber EFI_SECURITY_VIOLATION
1053 if (ret
!= EFI_SECURITY_VIOLATION
)
1058 dprint(L
"returning %r\n", ret
);
1062 // vim:fenc=utf-8:tw=75:noet