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