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_INVERSE
|
184 .state
= &trust_mok_list
,
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
|
197 .state
= &mok_policy
,
201 size_t n_mok_state_variables
= sizeof(mok_state_variable_data
) / sizeof(mok_state_variable_data
[0]);
202 struct mok_state_variable
*mok_state_variables
= &mok_state_variable_data
[0];
204 #define should_mirror_addend(v) (((v)->categorize_addend) && ((v)->categorize_addend(v) != VENDOR_ADDEND_NONE))
206 static inline BOOLEAN
NONNULL(1)
207 should_mirror_build_cert(struct mok_state_variable
*v
)
209 return (v
->build_cert
&& v
->build_cert_size
&&
210 *v
->build_cert
&& *v
->build_cert_size
) ? TRUE
: FALSE
;
213 static const uint8_t null_sha256
[32] = { 0, };
215 typedef UINTN SIZE_T
;
217 #define EFI_MAJOR_VERSION(tablep) ((UINT16)((((tablep)->Hdr.Revision) >> 16) & 0xfffful))
218 #define EFI_MINOR_VERSION(tablep) ((UINT16)(((tablep)->Hdr.Revision) & 0xfffful))
221 get_max_var_sz(UINT32 attrs
, SIZE_T
*max_var_szp
)
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;
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
;
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",
247 * I just don't trust implementations to not be showing static data
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
);
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()
263 * If no entries fit (i.e. sizeof(esl) + esl->SignatureSize > maxsz),
264 * returns EFI_BUFFER_TOO_SMALL;
267 mirror_one_esl(CHAR16
*name
, EFI_GUID
*guid
, UINT32 attrs
,
268 EFI_SIGNATURE_LIST
*esl
, EFI_SIGNATURE_DATA
*esd
,
271 EFI_STATUS efi_status
;
276 * We always assume esl->SignatureHeaderSize is 0 (and so far,
277 * that's true as per UEFI 2.8)
279 dprint(L
"Trying to add %lx signatures to \"%s\" of size %lx\n",
280 howmany
, name
, esl
->SignatureSize
);
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.
288 efi_status
= variable_create_esl(esd
, howmany
,
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
);
298 dprint(L
"new esl:\n");
299 dhexdumpat(var
, varsz
, 0);
301 efi_status
= SetVariable(name
, guid
, attrs
, varsz
, var
);
303 if (EFI_ERROR(efi_status
)) {
304 LogError(L
"Couldn't create mok variable \"%s\": %r\n",
305 varsz
, var
, efi_status
);
313 mirror_mok_db(CHAR16
*name
, CHAR8
*name8
, EFI_GUID
*guid
, UINT32 attrs
,
314 UINT8
*FullData
, SIZE_T FullDataSize
, BOOLEAN only_first
)
316 EFI_STATUS efi_status
= EFI_SUCCESS
;
319 efi_status
= get_max_var_sz(attrs
, &max_var_sz
);
320 if (EFI_ERROR(efi_status
) && efi_status
!= EFI_UNSUPPORTED
) {
321 LogError(L
"Could not get maximum variable size: %r",
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
;
333 efi_status
= SetVariable(name
, guid
, attrs
,
334 FullDataSize
, FullData
);
341 UINTN namelen
, namesz
;
343 namelen
= StrLen(name
);
344 namesz
= namelen
* 2;
351 namen
= AllocateZeroPool(namesz
);
353 LogError(L
"Could not allocate %lu bytes", namesz
);
354 return EFI_OUT_OF_RESOURCES
;
356 namen8
= AllocateZeroPool(namelen
);
359 LogError(L
"Could not allocate %lu bytes", namelen
);
360 return EFI_OUT_OF_RESOURCES
;
365 const SIZE_T minsz
= sizeof(EFI_SIGNATURE_LIST
)
366 + sizeof(EFI_SIGNATURE_DATA
)
368 BOOLEAN did_one
= FALSE
;
371 * Create any entries that can fit.
374 dprint(L
"full data for \"%s\":\n", name
);
375 dhexdumpat(FullData
, FullDataSize
, 0);
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
;
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
));
391 esd
= (EFI_SIGNATURE_DATA
*)(FullData
+ pos
);
392 if (pos
>= FullDataSize
)
394 if (esl
->SignatureListSize
== 0 || esl
->SignatureSize
== 0)
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
);
401 SPrint(namen
, namelen
, L
"%s%lu", name
, i
);
402 namen
[namelen
-1] = 0;
405 for (j
= 0; j
< namelen
; j
++)
406 namen8
[j
] = (CHAR8
)(namen
[j
] & 0xff);
407 namen8
[namelen
- 1] = 0;
411 * In case max_var_sz is computed dynamically, refresh the
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",
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
);
430 howmany
= MIN((max_var_sz
- sizeof(*esl
)) / esl
->SignatureSize
,
431 (esl_end_pos
- pos
) / esl
->SignatureSize
);
433 /* No signatures from this ESL can be mirrored in to a
434 * single variable, so skip it.
436 dprint(L
"skipping esl, pos:0x%llx->0x%llx\n", pos
, esl_end_pos
);
441 UINTN adj
= howmany
* esl
->SignatureSize
;
443 if (!only_first
&& i
== 0) {
444 dprint(L
"pos:0x%llx->0x%llx\n", pos
, pos
+ adj
);
451 efi_status
= mirror_one_esl(namen
, guid
, attrs
,
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",
460 dprint(L
"pos:0x%llx->0x%llx\n", pos
, pos
+ adj
);
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
) {
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.
483 efi_status
= variable_create_esl_with_one_signature(
484 null_sha256
, sizeof(null_sha256
),
485 &EFI_CERT_SHA256_GUID
, &SHIM_LOCK_GUID
,
488 * from here we don't really care if it works or
491 if (!EFI_ERROR(efi_status
) && var
&& varsz
) {
492 efi_status
= SetVariable(name
, guid
,
493 EFI_VARIABLE_BOOTSERVICE_ACCESS
494 | EFI_VARIABLE_RUNTIME_ACCESS
,
503 static EFI_STATUS
NONNULL(1)
504 mirror_one_mok_variable(struct mok_state_variable
*v
,
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
;
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;
519 if (v
->categorize_addend
)
520 addend_category
= v
->categorize_addend(v
);
523 * if it is, there's more data
525 if (v
->flags
& MOK_MIRROR_KEYDB
) {
528 * We're mirroring (into) an efi security database, aka an
529 * array of EFI_SIGNATURE_LIST. Its layout goes like:
531 * existing_variable_data
532 * existing_variable_data_size
533 * if flags & MOK_MIRROR_KEYDB
536 * build_cert_header (always sz=0)
537 * build_cert_esd[0] { owner, data }
538 * if addend==vendor_db
541 * vendor_db_header_n (always sz=0)
542 * vendor_db_esd_n[m] {{ owner, data }, ... }
543 * elif addend==vendor_cert
545 * vendor_cert_header (always sz=0)
546 * vendor_cert_esd[1] { owner, data }
548 * first we determine the size of the variable, then alloc
553 * *first* vendor_db or vendor_cert
555 switch (addend_category
) {
556 case VENDOR_ADDEND_DB
:
558 * if it's an ESL already, we use it wholesale
560 FullDataSize
+= *v
->addend_size
;
561 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
562 FullDataSize
, FullData
);
564 case VENDOR_ADDEND_X509
:
565 efi_status
= fill_esl_with_one_signature(*v
->addend
,
567 &EFI_CERT_TYPE_X509_GUID
,
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
+= addend_esl_sz
;
577 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
578 FullDataSize
, FullData
);
581 case VENDOR_ADDEND_NONE
:
582 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
583 FullDataSize
, FullData
);
588 * then the build cert if it's there
590 if (should_mirror_build_cert(v
)) {
591 efi_status
= fill_esl_with_one_signature(*v
->build_cert
,
593 &EFI_CERT_TYPE_X509_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
);
601 FullDataSize
+= build_cert_esl_sz
;
602 dprint(L
"FullDataSize:0x%lx FullData:0x%llx\n",
603 FullDataSize
, FullData
);
605 if (v
->user_cert_size
)
606 FullDataSize
+= *v
->user_cert_size
;
610 * we're always mirroring the original data, whether this is an efi
611 * security database or not
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
);
617 FullDataSize
+= v
->data_size
;
618 dprint(L
"FullDataSize:%lu FullData:0x%llx\n",
619 FullDataSize
, FullData
);
621 if (v
->data_size
== FullDataSize
)
625 * Now we have the full size
629 * allocate the buffer, or use the old one if it's just the
632 if (FullDataSize
== v
->data_size
) {
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
);
641 dprint(L
"FullDataSize:%lu FullData:0x%llx allocating FullData\n",
642 FullDataSize
, FullData
);
644 * make sure we've got some zeroes at the end, just
649 allocsz
= FullDataSize
+ sizeof(EFI_SIGNATURE_LIST
);
650 new = ALIGN_VALUE(allocsz
, 4096);
651 allocsz
= new == allocsz
? new + 4096 : new;
652 FullData
= AllocateZeroPool(allocsz
);
654 perror(L
"Failed to allocate %lu bytes for %s\n",
655 FullDataSize
, v
->name
);
656 return EFI_OUT_OF_RESOURCES
;
661 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
662 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
667 if (v
->flags
& MOK_MIRROR_KEYDB
) {
669 * first vendor_cert or vendor_db
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
);
678 case VENDOR_ADDEND_X509
:
679 efi_status
= fill_esl_with_one_signature(*v
->addend
,
681 &EFI_CERT_TYPE_X509_GUID
,
684 if (EFI_ERROR(efi_status
)) {
685 perror(L
"Could not add built-in cert to %s: %r\n",
686 v
->name
, efi_status
);
690 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
691 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
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
);
701 * then is the build cert
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
,
708 &EFI_CERT_TYPE_X509_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
);
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
);
720 if (v
->user_cert_size
) {
721 CopyMem(p
, *v
->user_cert
, *v
->user_cert_size
);
722 p
+= *v
->user_cert_size
;
727 * last bit is existing data, unless it's the only thing,
728 * in which case it's already there.
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
) {
734 CopyMem(p
, v
->data
, v
->data_size
);
737 dprint(L
"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n",
738 FullDataSize
, FullData
, p
, p
-(uintptr_t)FullData
);
742 * We always want to create our key databases, so in this case we
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
);
750 if (EFI_ERROR(efi_status
)) {
751 perror(L
"Failed to allocate %lu bytes for %s\n",
752 FullDataSize
, v
->name
);
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
);
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
,
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
);
774 if (FullDataSize
&& only_first
) {
777 * Measure this into PCR 7 in the Microsoft format
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
);
790 * Log this variable into whichever PCR the table
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
,
806 if (v
->data
&& v
->data_size
&& v
->data
!= FullData
) {
812 v
->data_size
= FullDataSize
;
813 dprint(L
"returning %r\n", efi_status
);
818 * Mirror a variable if it has an rtname, and preserve any
819 * EFI_SECURITY_VIOLATION status at the same time.
821 static EFI_STATUS
NONNULL(1)
822 maybe_mirror_one_mok_variable(struct mok_state_variable
*v
,
823 EFI_STATUS ret
, BOOLEAN only_first
)
825 EFI_STATUS efi_status
;
826 BOOLEAN present
= FALSE
;
829 if (only_first
&& (v
->flags
& MOK_MIRROR_DELETE_FIRST
)) {
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
);
835 efi_status
= mirror_one_mok_variable(v
, only_first
);
836 if (EFI_ERROR(efi_status
)) {
837 if (ret
!= EFI_SECURITY_VIOLATION
)
839 perror(L
"Could not create %s: %r\n", v
->rtname
,
844 present
= (v
->data
&& v
->data_size
) ? TRUE
: FALSE
;
848 if (v
->data_size
== sizeof(UINT8
) && v
->state
) {
849 *v
->state
= v
->data
[0];
855 EFI_STATUS
import_one_mok_state(struct mok_state_variable
*v
,
858 EFI_STATUS ret
= EFI_SUCCESS
;
859 EFI_STATUS efi_status
;
862 BOOLEAN
delete = FALSE
;
864 dprint(L
"importing mok state for \"%s\"\n", v
->name
);
866 if (!v
->data
&& !v
->data_size
) {
867 efi_status
= get_variable_attr(v
->name
,
868 &v
->data
, &v
->data_size
,
870 if (efi_status
== EFI_NOT_FOUND
&&
871 v
->flags
& MOK_VARIABLE_INVERSE
) {
872 v
->data
= AllocateZeroPool(4);
874 perror(L
"Out of memory\n");
875 return EFI_OUT_OF_RESOURCES
;
879 } else if (efi_status
== EFI_NOT_FOUND
) {
882 } else if (EFI_ERROR(efi_status
)) {
883 perror(L
"Could not verify %s: %r\n", v
->name
,
887 if (!(attrs
& v
->yes_attr
)) {
888 perror(L
"Variable %s is missing attributes:\n",
890 perror(L
" 0x%08x should have 0x%08x set.\n",
894 if (attrs
& v
->no_attr
) {
895 perror(L
"Variable %s has incorrect attribute:\n",
897 perror(L
" 0x%08x should not have 0x%08x set.\n",
901 if (v
->flags
& MOK_VARIABLE_INVERSE
) {
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
;
920 dprint(L
"maybe mirroring \"%s\". original data:\n", v
->name
);
921 if (v
->data
&& v
->data_size
) {
922 dhexdumpat(v
->data
, v
->data_size
, 0);
925 ret
= maybe_mirror_one_mok_variable(v
, ret
, only_first
);
926 dprint(L
"returning %r\n", ret
);
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.
936 * Any variable that isn't deleted and has ->measure == TRUE is then
937 * measured into the tpm.
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
943 EFI_STATUS
import_mok_state(EFI_HANDLE image_handle
)
946 EFI_STATUS ret
= EFI_SUCCESS
;
947 EFI_STATUS efi_status
;
949 user_insecure_mode
= 0;
953 UINT64 config_sz
= 0;
954 UINT8
*config_table
= NULL
;
956 struct mok_variable_config_entry config_template
;
958 dprint(L
"importing minimal mok state variables\n");
959 for (i
= 0; mok_state_variables
[i
].name
!= NULL
; i
++) {
960 struct mok_state_variable
*v
= &mok_state_variables
[i
];
962 efi_status
= import_one_mok_state(v
, TRUE
);
963 if (EFI_ERROR(efi_status
)) {
964 dprint(L
"import_one_mok_state(ih, \"%s\", TRUE): %r\n",
967 * don't clobber EFI_SECURITY_VIOLATION from some
968 * other variable in the list.
970 if (ret
!= EFI_SECURITY_VIOLATION
)
974 if (v
->data
&& v
->data_size
) {
975 config_sz
+= v
->data_size
;
976 config_sz
+= sizeof(config_template
);
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
987 config_sz
+= sizeof(config_template
);
988 npages
= ALIGN_VALUE(config_sz
, PAGE_SIZE
) >> EFI_PAGE_SHIFT
;
990 efi_status
= BS
->AllocatePages(
991 AllocateAnyPages
, EfiRuntimeServicesData
, npages
,
992 (EFI_PHYSICAL_ADDRESS
*)&config_table
);
993 if (EFI_ERROR(efi_status
) || !config_table
) {
994 console_print(L
"Allocating %lu pages for mok config table failed: %r\n",
998 ZeroMem(config_table
, npages
<< EFI_PAGE_SHIFT
);
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
];
1006 ZeroMem(&config_template
, sizeof(config_template
));
1007 strncpy(config_template
.name
, (CHAR8
*)v
->rtname8
, 255);
1008 config_template
.name
[255] = '\0';
1010 config_template
.data_size
= v
->data_size
;
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
);
1020 ZeroMem(&config_template
, sizeof(config_template
));
1021 CopyMem(p
, &config_template
, sizeof(config_template
));
1023 efi_status
= BS
->InstallConfigurationTable(&MOK_VARIABLE_STORE
,
1025 if (EFI_ERROR(efi_status
)) {
1026 console_print(L
"Couldn't install MoK configuration table\n");
1031 * This is really just to make it easy for userland.
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
];
1037 import_one_mok_state(v
, FALSE
);
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.
1045 dprint(L
"checking mok request\n");
1046 efi_status
= check_mok_request(image_handle
);
1047 dprint(L
"mok returned %r\n", efi_status
);
1048 if (EFI_ERROR(efi_status
)) {
1050 * don't clobber EFI_SECURITY_VIOLATION
1052 if (ret
!= EFI_SECURITY_VIOLATION
)
1057 dprint(L
"returning %r\n", ret
);
1061 // vim:fenc=utf-8:tw=75:noet