blob: ea8d2a4cf98c74413ef5148df0c881900ba3420c [file] [log] [blame]
Heinrich Schuchardt9827e842020-06-22 18:10:27 +02001/*
2 * UEFI runtime variable services
3 *
4 * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
AKASHI Takahiro200647a2020-07-30 16:33:59 +09005 * Copyright (c) 2020 Linaro Limited, Author: AKASHI Takahiro
Heinrich Schuchardt9827e842020-06-22 18:10:27 +02006 */
7
Heinrich Schuchardt9827e842020-06-22 18:10:27 +02008#include <efi_loader.h>
9#include <efi_variable.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020010#include <stdlib.h>
Ilias Apalodimascc0ead72024-04-05 09:50:58 +030011#include <u-boot/crc.h>
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020012
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +020013enum efi_secure_mode {
14 EFI_MODE_SETUP,
15 EFI_MODE_USER,
16 EFI_MODE_AUDIT,
17 EFI_MODE_DEPLOYED,
18};
19
Heinrich Schuchardt3a280332020-07-15 12:40:35 +020020struct efi_auth_var_name_type {
21 const u16 *name;
22 const efi_guid_t *guid;
23 const enum efi_auth_var_type type;
24};
25
Masahisa Kojima915e4272021-05-14 09:53:36 +090026const efi_guid_t efi_guid_image_security_database =
27 EFI_IMAGE_SECURITY_DATABASE_GUID;
28
Heinrich Schuchardt3a280332020-07-15 12:40:35 +020029static const struct efi_auth_var_name_type name_type[] = {
30 {u"PK", &efi_global_variable_guid, EFI_AUTH_VAR_PK},
31 {u"KEK", &efi_global_variable_guid, EFI_AUTH_VAR_KEK},
32 {u"db", &efi_guid_image_security_database, EFI_AUTH_VAR_DB},
33 {u"dbx", &efi_guid_image_security_database, EFI_AUTH_VAR_DBX},
Heinrich Schuchardt3a280332020-07-15 12:40:35 +020034 {u"dbt", &efi_guid_image_security_database, EFI_AUTH_VAR_DBT},
35 {u"dbr", &efi_guid_image_security_database, EFI_AUTH_VAR_DBR},
Heinrich Schuchardt65b616f2021-08-26 04:30:24 +020036 {u"AuditMode", &efi_global_variable_guid, EFI_AUTH_MODE},
37 {u"DeployedMode", &efi_global_variable_guid, EFI_AUTH_MODE},
Heinrich Schuchardt3a280332020-07-15 12:40:35 +020038};
39
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +020040static bool efi_secure_boot;
41static enum efi_secure_mode efi_secure_mode;
42
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020043/**
44 * efi_efi_get_variable() - retrieve value of a UEFI variable
45 *
46 * This function implements the GetVariable runtime service.
47 *
48 * See the Unified Extensible Firmware Interface (UEFI) specification for
49 * details.
50 *
51 * @variable_name: name of the variable
52 * @vendor: vendor GUID
53 * @attributes: attributes of the variable
54 * @data_size: size of the buffer to which the variable value is copied
55 * @data: buffer to which the variable value is copied
56 * Return: status code
57 */
58efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
59 const efi_guid_t *vendor, u32 *attributes,
60 efi_uintn_t *data_size, void *data)
61{
62 efi_status_t ret;
63
Heinrich Schuchardt282249d2022-01-16 14:15:31 +010064 EFI_ENTRY("\"%ls\" %pUs %p %p %p", variable_name, vendor, attributes,
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020065 data_size, data);
66
67 ret = efi_get_variable_int(variable_name, vendor, attributes,
68 data_size, data, NULL);
69
70 /* Remove EFI_VARIABLE_READ_ONLY flag */
71 if (attributes)
72 *attributes &= EFI_VARIABLE_MASK;
73
74 return EFI_EXIT(ret);
75}
76
77/**
78 * efi_set_variable() - set value of a UEFI variable
79 *
80 * This function implements the SetVariable runtime service.
81 *
82 * See the Unified Extensible Firmware Interface (UEFI) specification for
83 * details.
84 *
85 * @variable_name: name of the variable
86 * @vendor: vendor GUID
87 * @attributes: attributes of the variable
88 * @data_size: size of the buffer with the variable value
89 * @data: buffer with the variable value
90 * Return: status code
91 */
92efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
93 const efi_guid_t *vendor, u32 attributes,
94 efi_uintn_t data_size, const void *data)
95{
96 efi_status_t ret;
97
Heinrich Schuchardt282249d2022-01-16 14:15:31 +010098 EFI_ENTRY("\"%ls\" %pUs %x %zu %p", variable_name, vendor, attributes,
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020099 data_size, data);
100
101 /* Make sure that the EFI_VARIABLE_READ_ONLY flag is not set */
Heinrich Schuchardt698cfde2024-04-03 17:33:33 +0200102 if (attributes & ~EFI_VARIABLE_MASK)
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200103 ret = EFI_INVALID_PARAMETER;
104 else
105 ret = efi_set_variable_int(variable_name, vendor, attributes,
106 data_size, data, true);
107
108 return EFI_EXIT(ret);
109}
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200110
111/**
112 * efi_get_next_variable_name() - enumerate the current variable names
113 *
114 * @variable_name_size: size of variable_name buffer in byte
115 * @variable_name: name of uefi variable's name in u16
116 * @vendor: vendor's guid
117 *
118 * See the Unified Extensible Firmware Interface (UEFI) specification for
119 * details.
120 *
121 * Return: status code
122 */
123efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size,
124 u16 *variable_name,
125 efi_guid_t *vendor)
126{
127 efi_status_t ret;
128
Heinrich Schuchardt282249d2022-01-16 14:15:31 +0100129 EFI_ENTRY("%p \"%ls\" %pUs", variable_name_size, variable_name, vendor);
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200130
131 ret = efi_get_next_variable_name_int(variable_name_size, variable_name,
132 vendor);
133
134 return EFI_EXIT(ret);
135}
136
137/**
138 * efi_query_variable_info() - get information about EFI variables
139 *
140 * This function implements the QueryVariableInfo() runtime service.
141 *
142 * See the Unified Extensible Firmware Interface (UEFI) specification for
143 * details.
144 *
145 * @attributes: bitmask to select variables to be
146 * queried
147 * @maximum_variable_storage_size: maximum size of storage area for the
148 * selected variable types
149 * @remaining_variable_storage_size: remaining size of storage are for the
150 * selected variable types
151 * @maximum_variable_size: maximum size of a variable of the
152 * selected type
153 * Returns: status code
154 */
155efi_status_t EFIAPI efi_query_variable_info(
156 u32 attributes, u64 *maximum_variable_storage_size,
157 u64 *remaining_variable_storage_size,
158 u64 *maximum_variable_size)
159{
160 efi_status_t ret;
161
162 EFI_ENTRY("%x %p %p %p", attributes, maximum_variable_storage_size,
163 remaining_variable_storage_size, maximum_variable_size);
164
165 ret = efi_query_variable_info_int(attributes,
166 maximum_variable_storage_size,
167 remaining_variable_storage_size,
168 maximum_variable_size);
169
170 return EFI_EXIT(ret);
171}
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200172
Ilias Apalodimasa4d1b1b2020-07-23 15:49:49 +0300173efi_status_t __efi_runtime EFIAPI
174efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
175 u32 *attributes, efi_uintn_t *data_size, void *data)
176{
177 efi_status_t ret;
178
Ilias Apalodimasde708562024-04-18 15:54:52 +0300179 ret = efi_get_variable_mem(variable_name, guid, attributes, data_size,
180 data, NULL, EFI_VARIABLE_RUNTIME_ACCESS);
Ilias Apalodimasa4d1b1b2020-07-23 15:49:49 +0300181
182 /* Remove EFI_VARIABLE_READ_ONLY flag */
183 if (attributes)
184 *attributes &= EFI_VARIABLE_MASK;
185
186 return ret;
187}
188
189efi_status_t __efi_runtime EFIAPI
190efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
191 u16 *variable_name, efi_guid_t *guid)
192{
Ilias Apalodimasde708562024-04-18 15:54:52 +0300193 return efi_get_next_variable_name_mem(variable_name_size, variable_name,
194 guid, EFI_VARIABLE_RUNTIME_ACCESS);
Ilias Apalodimasa4d1b1b2020-07-23 15:49:49 +0300195}
196
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200197/**
198 * efi_set_secure_state - modify secure boot state variables
199 * @secure_boot: value of SecureBoot
200 * @setup_mode: value of SetupMode
201 * @audit_mode: value of AuditMode
202 * @deployed_mode: value of DeployedMode
203 *
204 * Modify secure boot status related variables as indicated.
205 *
206 * Return: status code
207 */
208static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode,
209 u8 audit_mode, u8 deployed_mode)
210{
211 efi_status_t ret;
212 const u32 attributes_ro = EFI_VARIABLE_BOOTSERVICE_ACCESS |
213 EFI_VARIABLE_RUNTIME_ACCESS |
214 EFI_VARIABLE_READ_ONLY;
215 const u32 attributes_rw = EFI_VARIABLE_BOOTSERVICE_ACCESS |
216 EFI_VARIABLE_RUNTIME_ACCESS;
217
218 efi_secure_boot = secure_boot;
219
Simon Glass90975372022-01-23 12:55:12 -0700220 ret = efi_set_variable_int(u"SecureBoot", &efi_global_variable_guid,
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200221 attributes_ro, sizeof(secure_boot),
222 &secure_boot, false);
223 if (ret != EFI_SUCCESS)
224 goto err;
225
Simon Glass90975372022-01-23 12:55:12 -0700226 ret = efi_set_variable_int(u"SetupMode", &efi_global_variable_guid,
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200227 attributes_ro, sizeof(setup_mode),
228 &setup_mode, false);
229 if (ret != EFI_SUCCESS)
230 goto err;
231
Simon Glass90975372022-01-23 12:55:12 -0700232 ret = efi_set_variable_int(u"AuditMode", &efi_global_variable_guid,
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200233 audit_mode || setup_mode ?
234 attributes_ro : attributes_rw,
235 sizeof(audit_mode), &audit_mode, false);
236 if (ret != EFI_SUCCESS)
237 goto err;
238
Simon Glass90975372022-01-23 12:55:12 -0700239 ret = efi_set_variable_int(u"DeployedMode",
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200240 &efi_global_variable_guid,
241 audit_mode || deployed_mode || setup_mode ?
242 attributes_ro : attributes_rw,
243 sizeof(deployed_mode), &deployed_mode,
244 false);
245err:
246 return ret;
247}
248
249/**
250 * efi_transfer_secure_state - handle a secure boot state transition
251 * @mode: new state
252 *
253 * Depending on @mode, secure boot related variables are updated.
254 * Those variables are *read-only* for users, efi_set_variable_int()
255 * is called here.
256 *
257 * Return: status code
258 */
259static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
260{
261 efi_status_t ret;
262
263 EFI_PRINT("Switching secure state from %d to %d\n", efi_secure_mode,
264 mode);
265
266 if (mode == EFI_MODE_DEPLOYED) {
267 ret = efi_set_secure_state(1, 0, 0, 1);
268 if (ret != EFI_SUCCESS)
269 goto err;
270 } else if (mode == EFI_MODE_AUDIT) {
Simon Glass90975372022-01-23 12:55:12 -0700271 ret = efi_set_variable_int(u"PK", &efi_global_variable_guid,
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200272 EFI_VARIABLE_BOOTSERVICE_ACCESS |
273 EFI_VARIABLE_RUNTIME_ACCESS,
274 0, NULL, false);
275 if (ret != EFI_SUCCESS)
276 goto err;
277
278 ret = efi_set_secure_state(0, 1, 1, 0);
279 if (ret != EFI_SUCCESS)
280 goto err;
281 } else if (mode == EFI_MODE_USER) {
282 ret = efi_set_secure_state(1, 0, 0, 0);
283 if (ret != EFI_SUCCESS)
284 goto err;
285 } else if (mode == EFI_MODE_SETUP) {
286 ret = efi_set_secure_state(0, 1, 0, 0);
287 if (ret != EFI_SUCCESS)
288 goto err;
289 } else {
290 return EFI_INVALID_PARAMETER;
291 }
292
293 efi_secure_mode = mode;
294
295 return EFI_SUCCESS;
296
297err:
298 /* TODO: What action should be taken here? */
299 printf("ERROR: Secure state transition failed\n");
300 return ret;
301}
302
303efi_status_t efi_init_secure_state(void)
304{
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200305 enum efi_secure_mode mode;
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200306 u8 efi_vendor_keys = 0;
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200307 efi_uintn_t size;
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200308 efi_status_t ret;
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200309 u8 deployed_mode = 0;
310 u8 audit_mode = 0;
311 u8 setup_mode = 1;
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200312
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200313 if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) {
314 size = sizeof(deployed_mode);
315 ret = efi_get_variable_int(u"DeployedMode", &efi_global_variable_guid,
316 NULL, &size, &deployed_mode, NULL);
317 size = sizeof(audit_mode);
318 ret = efi_get_variable_int(u"AuditMode", &efi_global_variable_guid,
319 NULL, &size, &audit_mode, NULL);
320 size = 0;
321 ret = efi_get_variable_int(u"PK", &efi_global_variable_guid,
322 NULL, &size, NULL, NULL);
323 if (ret == EFI_BUFFER_TOO_SMALL) {
324 setup_mode = 0;
325 audit_mode = 0;
326 } else {
327 setup_mode = 1;
328 deployed_mode = 0;
329 }
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200330 }
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200331 if (deployed_mode)
332 mode = EFI_MODE_DEPLOYED;
333 else if (audit_mode)
334 mode = EFI_MODE_AUDIT;
335 else if (setup_mode)
336 mode = EFI_MODE_SETUP;
337 else
338 mode = EFI_MODE_USER;
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200339
340 ret = efi_transfer_secure_state(mode);
341 if (ret != EFI_SUCCESS)
342 return ret;
343
344 /* As we do not provide vendor keys this variable is always 0. */
Simon Glass90975372022-01-23 12:55:12 -0700345 ret = efi_set_variable_int(u"VendorKeys",
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200346 &efi_global_variable_guid,
347 EFI_VARIABLE_BOOTSERVICE_ACCESS |
348 EFI_VARIABLE_RUNTIME_ACCESS |
349 EFI_VARIABLE_READ_ONLY,
350 sizeof(efi_vendor_keys),
351 &efi_vendor_keys, false);
352 return ret;
353}
354
355/**
356 * efi_secure_boot_enabled - return if secure boot is enabled or not
357 *
358 * Return: true if enabled, false if disabled
359 */
360bool efi_secure_boot_enabled(void)
361{
362 return efi_secure_boot;
363}
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200364
Heinrich Schuchardt1ad2f0d2021-09-09 07:12:14 +0200365enum efi_auth_var_type efi_auth_var_get_type(const u16 *name,
366 const efi_guid_t *guid)
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200367{
368 for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
369 if (!u16_strcmp(name, name_type[i].name) &&
370 !guidcmp(guid, name_type[i].guid))
371 return name_type[i].type;
372 }
373 return EFI_AUTH_VAR_NONE;
374}
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200375
Heinrich Schuchardtcbd28022021-09-09 08:22:58 +0200376const efi_guid_t *efi_auth_var_get_guid(const u16 *name)
377{
378 for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
379 if (!u16_strcmp(name, name_type[i].name))
380 return name_type[i].guid;
381 }
382 return &efi_global_variable_guid;
383}
384
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200385/**
386 * efi_get_var() - read value of an EFI variable
387 *
388 * @name: variable name
389 * @start: vendor GUID
390 * @size: size of allocated buffer
391 *
392 * Return: buffer with variable data or NULL
393 */
Heinrich Schuchardt1ad2f0d2021-09-09 07:12:14 +0200394void *efi_get_var(const u16 *name, const efi_guid_t *vendor, efi_uintn_t *size)
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200395{
396 efi_status_t ret;
397 void *buf = NULL;
398
399 *size = 0;
400 ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
401 if (ret == EFI_BUFFER_TOO_SMALL) {
402 buf = malloc(*size);
403 if (!buf)
404 return NULL;
405 ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
406 }
407
408 if (ret != EFI_SUCCESS) {
409 free(buf);
410 *size = 0;
411 return NULL;
412 }
413
414 return buf;
415}
Ilias Apalodimascc0ead72024-04-05 09:50:58 +0300416
417/**
Heinrich Schuchardt3390fdd2024-04-18 04:32:02 +0200418 * efi_var_collect() - Copy EFI variables matching attributes mask
Ilias Apalodimascc0ead72024-04-05 09:50:58 +0300419 *
420 * @bufp: buffer containing variable collection
421 * @lenp: buffer length
422 * @attr_mask: mask of matched attributes
423 *
424 * Return: Status code
425 */
426efi_status_t __maybe_unused efi_var_collect(struct efi_var_file **bufp, loff_t *lenp,
427 u32 check_attr_mask)
428{
429 size_t len = EFI_VAR_BUF_SIZE;
430 struct efi_var_file *buf;
431 struct efi_var_entry *var, *old_var;
432 size_t old_var_name_length = 2;
433
434 *bufp = NULL; /* Avoid double free() */
435 buf = calloc(1, len);
436 if (!buf)
437 return EFI_OUT_OF_RESOURCES;
438 var = buf->var;
439 old_var = var;
440 for (;;) {
441 efi_uintn_t data_length, var_name_length;
442 u8 *data;
443 efi_status_t ret;
444
445 if ((uintptr_t)buf + len <=
446 (uintptr_t)var->name + old_var_name_length)
447 return EFI_BUFFER_TOO_SMALL;
448
449 var_name_length = (uintptr_t)buf + len - (uintptr_t)var->name;
450 memcpy(var->name, old_var->name, old_var_name_length);
451 guidcpy(&var->guid, &old_var->guid);
452 ret = efi_get_next_variable_name_int(
453 &var_name_length, var->name, &var->guid);
454 if (ret == EFI_NOT_FOUND)
455 break;
456 if (ret != EFI_SUCCESS) {
457 free(buf);
458 return ret;
459 }
460 old_var_name_length = var_name_length;
461 old_var = var;
462
463 data = (u8 *)var->name + old_var_name_length;
464 data_length = (uintptr_t)buf + len - (uintptr_t)data;
465 ret = efi_get_variable_int(var->name, &var->guid,
466 &var->attr, &data_length, data,
467 &var->time);
468 if (ret != EFI_SUCCESS) {
469 free(buf);
470 return ret;
471 }
472 if ((var->attr & check_attr_mask) == check_attr_mask) {
473 var->length = data_length;
474 var = (struct efi_var_entry *)ALIGN((uintptr_t)data + data_length, 8);
475 }
476 }
477
478 buf->reserved = 0;
479 buf->magic = EFI_VAR_FILE_MAGIC;
480 len = (uintptr_t)var - (uintptr_t)buf;
481 buf->crc32 = crc32(0, (u8 *)buf->var,
482 len - sizeof(struct efi_var_file));
483 buf->length = len;
484 *bufp = buf;
485 *lenp = len;
486
487 return EFI_SUCCESS;
488}