blob: 4b34a58b4cf734e578898591270beab52015c45d [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 Schuchardt955a3212025-01-16 20:26:59 +01008#define LOG_CATEGORY LOGC_EFI
9
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020010#include <efi_loader.h>
11#include <efi_variable.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020012#include <stdlib.h>
Ilias Apalodimascc0ead72024-04-05 09:50:58 +030013#include <u-boot/crc.h>
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020014
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +020015enum efi_secure_mode {
16 EFI_MODE_SETUP,
17 EFI_MODE_USER,
18 EFI_MODE_AUDIT,
19 EFI_MODE_DEPLOYED,
20};
21
Heinrich Schuchardt3a280332020-07-15 12:40:35 +020022struct efi_auth_var_name_type {
23 const u16 *name;
24 const efi_guid_t *guid;
25 const enum efi_auth_var_type type;
26};
27
Masahisa Kojima915e4272021-05-14 09:53:36 +090028const efi_guid_t efi_guid_image_security_database =
29 EFI_IMAGE_SECURITY_DATABASE_GUID;
30
Heinrich Schuchardt3a280332020-07-15 12:40:35 +020031static const struct efi_auth_var_name_type name_type[] = {
32 {u"PK", &efi_global_variable_guid, EFI_AUTH_VAR_PK},
33 {u"KEK", &efi_global_variable_guid, EFI_AUTH_VAR_KEK},
34 {u"db", &efi_guid_image_security_database, EFI_AUTH_VAR_DB},
35 {u"dbx", &efi_guid_image_security_database, EFI_AUTH_VAR_DBX},
Heinrich Schuchardt3a280332020-07-15 12:40:35 +020036 {u"dbt", &efi_guid_image_security_database, EFI_AUTH_VAR_DBT},
37 {u"dbr", &efi_guid_image_security_database, EFI_AUTH_VAR_DBR},
Heinrich Schuchardt65b616f2021-08-26 04:30:24 +020038 {u"AuditMode", &efi_global_variable_guid, EFI_AUTH_MODE},
39 {u"DeployedMode", &efi_global_variable_guid, EFI_AUTH_MODE},
Heinrich Schuchardt3a280332020-07-15 12:40:35 +020040};
41
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +020042static bool efi_secure_boot;
43static enum efi_secure_mode efi_secure_mode;
44
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020045/**
46 * efi_efi_get_variable() - retrieve value of a UEFI variable
47 *
48 * This function implements the GetVariable runtime service.
49 *
50 * See the Unified Extensible Firmware Interface (UEFI) specification for
51 * details.
52 *
53 * @variable_name: name of the variable
54 * @vendor: vendor GUID
55 * @attributes: attributes of the variable
56 * @data_size: size of the buffer to which the variable value is copied
57 * @data: buffer to which the variable value is copied
58 * Return: status code
59 */
60efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
61 const efi_guid_t *vendor, u32 *attributes,
62 efi_uintn_t *data_size, void *data)
63{
64 efi_status_t ret;
65
Heinrich Schuchardt282249d2022-01-16 14:15:31 +010066 EFI_ENTRY("\"%ls\" %pUs %p %p %p", variable_name, vendor, attributes,
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020067 data_size, data);
68
69 ret = efi_get_variable_int(variable_name, vendor, attributes,
70 data_size, data, NULL);
71
72 /* Remove EFI_VARIABLE_READ_ONLY flag */
73 if (attributes)
74 *attributes &= EFI_VARIABLE_MASK;
75
76 return EFI_EXIT(ret);
77}
78
79/**
80 * efi_set_variable() - set value of a UEFI variable
81 *
82 * This function implements the SetVariable runtime service.
83 *
84 * See the Unified Extensible Firmware Interface (UEFI) specification for
85 * details.
86 *
87 * @variable_name: name of the variable
88 * @vendor: vendor GUID
89 * @attributes: attributes of the variable
90 * @data_size: size of the buffer with the variable value
91 * @data: buffer with the variable value
92 * Return: status code
93 */
94efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
95 const efi_guid_t *vendor, u32 attributes,
96 efi_uintn_t data_size, const void *data)
97{
98 efi_status_t ret;
99
Heinrich Schuchardt282249d2022-01-16 14:15:31 +0100100 EFI_ENTRY("\"%ls\" %pUs %x %zu %p", variable_name, vendor, attributes,
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200101 data_size, data);
102
103 /* Make sure that the EFI_VARIABLE_READ_ONLY flag is not set */
Heinrich Schuchardt698cfde2024-04-03 17:33:33 +0200104 if (attributes & ~EFI_VARIABLE_MASK)
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200105 ret = EFI_INVALID_PARAMETER;
106 else
107 ret = efi_set_variable_int(variable_name, vendor, attributes,
108 data_size, data, true);
109
110 return EFI_EXIT(ret);
111}
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200112
113/**
114 * efi_get_next_variable_name() - enumerate the current variable names
115 *
116 * @variable_name_size: size of variable_name buffer in byte
117 * @variable_name: name of uefi variable's name in u16
118 * @vendor: vendor's guid
119 *
120 * See the Unified Extensible Firmware Interface (UEFI) specification for
121 * details.
122 *
123 * Return: status code
124 */
125efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size,
126 u16 *variable_name,
127 efi_guid_t *vendor)
128{
129 efi_status_t ret;
130
Heinrich Schuchardt282249d2022-01-16 14:15:31 +0100131 EFI_ENTRY("%p \"%ls\" %pUs", variable_name_size, variable_name, vendor);
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200132
133 ret = efi_get_next_variable_name_int(variable_name_size, variable_name,
134 vendor);
135
136 return EFI_EXIT(ret);
137}
138
139/**
140 * efi_query_variable_info() - get information about EFI variables
141 *
142 * This function implements the QueryVariableInfo() runtime service.
143 *
144 * See the Unified Extensible Firmware Interface (UEFI) specification for
145 * details.
146 *
147 * @attributes: bitmask to select variables to be
148 * queried
149 * @maximum_variable_storage_size: maximum size of storage area for the
150 * selected variable types
151 * @remaining_variable_storage_size: remaining size of storage are for the
152 * selected variable types
153 * @maximum_variable_size: maximum size of a variable of the
154 * selected type
155 * Returns: status code
156 */
157efi_status_t EFIAPI efi_query_variable_info(
158 u32 attributes, u64 *maximum_variable_storage_size,
159 u64 *remaining_variable_storage_size,
160 u64 *maximum_variable_size)
161{
162 efi_status_t ret;
163
164 EFI_ENTRY("%x %p %p %p", attributes, maximum_variable_storage_size,
165 remaining_variable_storage_size, maximum_variable_size);
166
167 ret = efi_query_variable_info_int(attributes,
168 maximum_variable_storage_size,
169 remaining_variable_storage_size,
170 maximum_variable_size);
171
172 return EFI_EXIT(ret);
173}
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200174
Ilias Apalodimasa4d1b1b2020-07-23 15:49:49 +0300175efi_status_t __efi_runtime EFIAPI
176efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
177 u32 *attributes, efi_uintn_t *data_size, void *data)
178{
179 efi_status_t ret;
180
Ilias Apalodimasde708562024-04-18 15:54:52 +0300181 ret = efi_get_variable_mem(variable_name, guid, attributes, data_size,
182 data, NULL, EFI_VARIABLE_RUNTIME_ACCESS);
Ilias Apalodimasa4d1b1b2020-07-23 15:49:49 +0300183
184 /* Remove EFI_VARIABLE_READ_ONLY flag */
185 if (attributes)
186 *attributes &= EFI_VARIABLE_MASK;
187
188 return ret;
189}
190
191efi_status_t __efi_runtime EFIAPI
192efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
193 u16 *variable_name, efi_guid_t *guid)
194{
Ilias Apalodimasde708562024-04-18 15:54:52 +0300195 return efi_get_next_variable_name_mem(variable_name_size, variable_name,
196 guid, EFI_VARIABLE_RUNTIME_ACCESS);
Ilias Apalodimasa4d1b1b2020-07-23 15:49:49 +0300197}
198
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200199/**
200 * efi_set_secure_state - modify secure boot state variables
201 * @secure_boot: value of SecureBoot
202 * @setup_mode: value of SetupMode
203 * @audit_mode: value of AuditMode
204 * @deployed_mode: value of DeployedMode
205 *
206 * Modify secure boot status related variables as indicated.
207 *
208 * Return: status code
209 */
210static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode,
211 u8 audit_mode, u8 deployed_mode)
212{
213 efi_status_t ret;
214 const u32 attributes_ro = EFI_VARIABLE_BOOTSERVICE_ACCESS |
215 EFI_VARIABLE_RUNTIME_ACCESS |
216 EFI_VARIABLE_READ_ONLY;
217 const u32 attributes_rw = EFI_VARIABLE_BOOTSERVICE_ACCESS |
218 EFI_VARIABLE_RUNTIME_ACCESS;
219
220 efi_secure_boot = secure_boot;
221
Simon Glass90975372022-01-23 12:55:12 -0700222 ret = efi_set_variable_int(u"SecureBoot", &efi_global_variable_guid,
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200223 attributes_ro, sizeof(secure_boot),
224 &secure_boot, false);
225 if (ret != EFI_SUCCESS)
226 goto err;
227
Simon Glass90975372022-01-23 12:55:12 -0700228 ret = efi_set_variable_int(u"SetupMode", &efi_global_variable_guid,
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200229 attributes_ro, sizeof(setup_mode),
230 &setup_mode, false);
231 if (ret != EFI_SUCCESS)
232 goto err;
233
Simon Glass90975372022-01-23 12:55:12 -0700234 ret = efi_set_variable_int(u"AuditMode", &efi_global_variable_guid,
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200235 audit_mode || setup_mode ?
236 attributes_ro : attributes_rw,
237 sizeof(audit_mode), &audit_mode, false);
238 if (ret != EFI_SUCCESS)
239 goto err;
240
Simon Glass90975372022-01-23 12:55:12 -0700241 ret = efi_set_variable_int(u"DeployedMode",
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200242 &efi_global_variable_guid,
243 audit_mode || deployed_mode || setup_mode ?
244 attributes_ro : attributes_rw,
245 sizeof(deployed_mode), &deployed_mode,
246 false);
247err:
248 return ret;
249}
250
251/**
252 * efi_transfer_secure_state - handle a secure boot state transition
253 * @mode: new state
254 *
255 * Depending on @mode, secure boot related variables are updated.
256 * Those variables are *read-only* for users, efi_set_variable_int()
257 * is called here.
258 *
259 * Return: status code
260 */
261static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
262{
263 efi_status_t ret;
264
265 EFI_PRINT("Switching secure state from %d to %d\n", efi_secure_mode,
266 mode);
267
268 if (mode == EFI_MODE_DEPLOYED) {
269 ret = efi_set_secure_state(1, 0, 0, 1);
270 if (ret != EFI_SUCCESS)
271 goto err;
272 } else if (mode == EFI_MODE_AUDIT) {
Simon Glass90975372022-01-23 12:55:12 -0700273 ret = efi_set_variable_int(u"PK", &efi_global_variable_guid,
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200274 EFI_VARIABLE_BOOTSERVICE_ACCESS |
275 EFI_VARIABLE_RUNTIME_ACCESS,
276 0, NULL, false);
277 if (ret != EFI_SUCCESS)
278 goto err;
279
280 ret = efi_set_secure_state(0, 1, 1, 0);
281 if (ret != EFI_SUCCESS)
282 goto err;
283 } else if (mode == EFI_MODE_USER) {
284 ret = efi_set_secure_state(1, 0, 0, 0);
285 if (ret != EFI_SUCCESS)
286 goto err;
287 } else if (mode == EFI_MODE_SETUP) {
288 ret = efi_set_secure_state(0, 1, 0, 0);
289 if (ret != EFI_SUCCESS)
290 goto err;
291 } else {
292 return EFI_INVALID_PARAMETER;
293 }
294
295 efi_secure_mode = mode;
296
297 return EFI_SUCCESS;
298
299err:
300 /* TODO: What action should be taken here? */
301 printf("ERROR: Secure state transition failed\n");
302 return ret;
303}
304
305efi_status_t efi_init_secure_state(void)
306{
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200307 enum efi_secure_mode mode;
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200308 u8 efi_vendor_keys = 0;
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200309 efi_uintn_t size;
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200310 efi_status_t ret;
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200311 u8 deployed_mode = 0;
312 u8 audit_mode = 0;
313 u8 setup_mode = 1;
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200314
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200315 if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) {
316 size = sizeof(deployed_mode);
317 ret = efi_get_variable_int(u"DeployedMode", &efi_global_variable_guid,
318 NULL, &size, &deployed_mode, NULL);
319 size = sizeof(audit_mode);
320 ret = efi_get_variable_int(u"AuditMode", &efi_global_variable_guid,
321 NULL, &size, &audit_mode, NULL);
322 size = 0;
323 ret = efi_get_variable_int(u"PK", &efi_global_variable_guid,
324 NULL, &size, NULL, NULL);
325 if (ret == EFI_BUFFER_TOO_SMALL) {
326 setup_mode = 0;
327 audit_mode = 0;
328 } else {
329 setup_mode = 1;
330 deployed_mode = 0;
331 }
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200332 }
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200333 if (deployed_mode)
334 mode = EFI_MODE_DEPLOYED;
335 else if (audit_mode)
336 mode = EFI_MODE_AUDIT;
337 else if (setup_mode)
338 mode = EFI_MODE_SETUP;
339 else
340 mode = EFI_MODE_USER;
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200341
342 ret = efi_transfer_secure_state(mode);
343 if (ret != EFI_SUCCESS)
344 return ret;
345
346 /* As we do not provide vendor keys this variable is always 0. */
Simon Glass90975372022-01-23 12:55:12 -0700347 ret = efi_set_variable_int(u"VendorKeys",
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200348 &efi_global_variable_guid,
349 EFI_VARIABLE_BOOTSERVICE_ACCESS |
350 EFI_VARIABLE_RUNTIME_ACCESS |
351 EFI_VARIABLE_READ_ONLY,
352 sizeof(efi_vendor_keys),
353 &efi_vendor_keys, false);
354 return ret;
355}
356
357/**
358 * efi_secure_boot_enabled - return if secure boot is enabled or not
359 *
360 * Return: true if enabled, false if disabled
361 */
362bool efi_secure_boot_enabled(void)
363{
364 return efi_secure_boot;
365}
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200366
Heinrich Schuchardt1ad2f0d2021-09-09 07:12:14 +0200367enum efi_auth_var_type efi_auth_var_get_type(const u16 *name,
368 const efi_guid_t *guid)
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200369{
370 for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
371 if (!u16_strcmp(name, name_type[i].name) &&
372 !guidcmp(guid, name_type[i].guid))
373 return name_type[i].type;
374 }
375 return EFI_AUTH_VAR_NONE;
376}
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200377
Heinrich Schuchardtcbd28022021-09-09 08:22:58 +0200378const efi_guid_t *efi_auth_var_get_guid(const u16 *name)
379{
380 for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
381 if (!u16_strcmp(name, name_type[i].name))
382 return name_type[i].guid;
383 }
384 return &efi_global_variable_guid;
385}
386
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200387/**
388 * efi_get_var() - read value of an EFI variable
389 *
390 * @name: variable name
391 * @start: vendor GUID
392 * @size: size of allocated buffer
393 *
394 * Return: buffer with variable data or NULL
395 */
Heinrich Schuchardt1ad2f0d2021-09-09 07:12:14 +0200396void *efi_get_var(const u16 *name, const efi_guid_t *vendor, efi_uintn_t *size)
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200397{
398 efi_status_t ret;
399 void *buf = NULL;
400
401 *size = 0;
402 ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
403 if (ret == EFI_BUFFER_TOO_SMALL) {
404 buf = malloc(*size);
405 if (!buf)
406 return NULL;
407 ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
408 }
409
410 if (ret != EFI_SUCCESS) {
411 free(buf);
412 *size = 0;
413 return NULL;
414 }
415
416 return buf;
417}
Ilias Apalodimascc0ead72024-04-05 09:50:58 +0300418
419/**
Heinrich Schuchardt3390fdd2024-04-18 04:32:02 +0200420 * efi_var_collect() - Copy EFI variables matching attributes mask
Ilias Apalodimascc0ead72024-04-05 09:50:58 +0300421 *
422 * @bufp: buffer containing variable collection
423 * @lenp: buffer length
424 * @attr_mask: mask of matched attributes
425 *
426 * Return: Status code
427 */
428efi_status_t __maybe_unused efi_var_collect(struct efi_var_file **bufp, loff_t *lenp,
429 u32 check_attr_mask)
430{
431 size_t len = EFI_VAR_BUF_SIZE;
432 struct efi_var_file *buf;
433 struct efi_var_entry *var, *old_var;
434 size_t old_var_name_length = 2;
435
436 *bufp = NULL; /* Avoid double free() */
437 buf = calloc(1, len);
438 if (!buf)
439 return EFI_OUT_OF_RESOURCES;
440 var = buf->var;
441 old_var = var;
442 for (;;) {
443 efi_uintn_t data_length, var_name_length;
444 u8 *data;
445 efi_status_t ret;
446
447 if ((uintptr_t)buf + len <=
448 (uintptr_t)var->name + old_var_name_length)
449 return EFI_BUFFER_TOO_SMALL;
450
451 var_name_length = (uintptr_t)buf + len - (uintptr_t)var->name;
452 memcpy(var->name, old_var->name, old_var_name_length);
453 guidcpy(&var->guid, &old_var->guid);
454 ret = efi_get_next_variable_name_int(
455 &var_name_length, var->name, &var->guid);
456 if (ret == EFI_NOT_FOUND)
457 break;
458 if (ret != EFI_SUCCESS) {
459 free(buf);
460 return ret;
461 }
462 old_var_name_length = var_name_length;
463 old_var = var;
464
465 data = (u8 *)var->name + old_var_name_length;
466 data_length = (uintptr_t)buf + len - (uintptr_t)data;
467 ret = efi_get_variable_int(var->name, &var->guid,
468 &var->attr, &data_length, data,
469 &var->time);
470 if (ret != EFI_SUCCESS) {
471 free(buf);
472 return ret;
473 }
474 if ((var->attr & check_attr_mask) == check_attr_mask) {
475 var->length = data_length;
476 var = (struct efi_var_entry *)ALIGN((uintptr_t)data + data_length, 8);
477 }
478 }
479
480 buf->reserved = 0;
481 buf->magic = EFI_VAR_FILE_MAGIC;
482 len = (uintptr_t)var - (uintptr_t)buf;
483 buf->crc32 = crc32(0, (u8 *)buf->var,
484 len - sizeof(struct efi_var_file));
485 buf->length = len;
486 *bufp = buf;
487 *lenp = len;
488
489 return EFI_SUCCESS;
490}