blob: 16b2c3d48828a03ed2593a9614982489b72643aa [file] [log] [blame]
Heinrich Schuchardt9827e842020-06-22 18:10:27 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * UEFI runtime variable services
4 *
5 * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
AKASHI Takahiro200647a2020-07-30 16:33:59 +09006 * Copyright (c) 2020 Linaro Limited, Author: AKASHI Takahiro
Heinrich Schuchardt9827e842020-06-22 18:10:27 +02007 */
8
Heinrich Schuchardt9827e842020-06-22 18:10:27 +02009#include <efi_loader.h>
10#include <efi_variable.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020011#include <stdlib.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
Masami Hiramatsuaee53302021-07-01 00:49:48 +0900165 if (!maximum_variable_storage_size ||
166 !remaining_variable_storage_size ||
Masahisa Kojima1fd781f2023-02-02 22:53:35 +0900167 !maximum_variable_size)
Masami Hiramatsuaee53302021-07-01 00:49:48 +0900168 return EFI_EXIT(EFI_INVALID_PARAMETER);
169
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200170 ret = efi_query_variable_info_int(attributes,
171 maximum_variable_storage_size,
172 remaining_variable_storage_size,
173 maximum_variable_size);
174
175 return EFI_EXIT(ret);
176}
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200177
Ilias Apalodimasa4d1b1b2020-07-23 15:49:49 +0300178efi_status_t __efi_runtime EFIAPI
179efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
180 u32 *attributes, efi_uintn_t *data_size, void *data)
181{
182 efi_status_t ret;
183
184 ret = efi_get_variable_mem(variable_name, guid, attributes, data_size, data, NULL);
185
186 /* Remove EFI_VARIABLE_READ_ONLY flag */
187 if (attributes)
188 *attributes &= EFI_VARIABLE_MASK;
189
190 return ret;
191}
192
193efi_status_t __efi_runtime EFIAPI
194efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
195 u16 *variable_name, efi_guid_t *guid)
196{
197 return efi_get_next_variable_name_mem(variable_name_size, variable_name, guid);
198}
199
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200200/**
201 * efi_set_secure_state - modify secure boot state variables
202 * @secure_boot: value of SecureBoot
203 * @setup_mode: value of SetupMode
204 * @audit_mode: value of AuditMode
205 * @deployed_mode: value of DeployedMode
206 *
207 * Modify secure boot status related variables as indicated.
208 *
209 * Return: status code
210 */
211static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode,
212 u8 audit_mode, u8 deployed_mode)
213{
214 efi_status_t ret;
215 const u32 attributes_ro = EFI_VARIABLE_BOOTSERVICE_ACCESS |
216 EFI_VARIABLE_RUNTIME_ACCESS |
217 EFI_VARIABLE_READ_ONLY;
218 const u32 attributes_rw = EFI_VARIABLE_BOOTSERVICE_ACCESS |
219 EFI_VARIABLE_RUNTIME_ACCESS;
220
221 efi_secure_boot = secure_boot;
222
Simon Glass90975372022-01-23 12:55:12 -0700223 ret = efi_set_variable_int(u"SecureBoot", &efi_global_variable_guid,
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200224 attributes_ro, sizeof(secure_boot),
225 &secure_boot, false);
226 if (ret != EFI_SUCCESS)
227 goto err;
228
Simon Glass90975372022-01-23 12:55:12 -0700229 ret = efi_set_variable_int(u"SetupMode", &efi_global_variable_guid,
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200230 attributes_ro, sizeof(setup_mode),
231 &setup_mode, false);
232 if (ret != EFI_SUCCESS)
233 goto err;
234
Simon Glass90975372022-01-23 12:55:12 -0700235 ret = efi_set_variable_int(u"AuditMode", &efi_global_variable_guid,
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200236 audit_mode || setup_mode ?
237 attributes_ro : attributes_rw,
238 sizeof(audit_mode), &audit_mode, false);
239 if (ret != EFI_SUCCESS)
240 goto err;
241
Simon Glass90975372022-01-23 12:55:12 -0700242 ret = efi_set_variable_int(u"DeployedMode",
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200243 &efi_global_variable_guid,
244 audit_mode || deployed_mode || setup_mode ?
245 attributes_ro : attributes_rw,
246 sizeof(deployed_mode), &deployed_mode,
247 false);
248err:
249 return ret;
250}
251
252/**
253 * efi_transfer_secure_state - handle a secure boot state transition
254 * @mode: new state
255 *
256 * Depending on @mode, secure boot related variables are updated.
257 * Those variables are *read-only* for users, efi_set_variable_int()
258 * is called here.
259 *
260 * Return: status code
261 */
262static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
263{
264 efi_status_t ret;
265
266 EFI_PRINT("Switching secure state from %d to %d\n", efi_secure_mode,
267 mode);
268
269 if (mode == EFI_MODE_DEPLOYED) {
270 ret = efi_set_secure_state(1, 0, 0, 1);
271 if (ret != EFI_SUCCESS)
272 goto err;
273 } else if (mode == EFI_MODE_AUDIT) {
Simon Glass90975372022-01-23 12:55:12 -0700274 ret = efi_set_variable_int(u"PK", &efi_global_variable_guid,
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200275 EFI_VARIABLE_BOOTSERVICE_ACCESS |
276 EFI_VARIABLE_RUNTIME_ACCESS,
277 0, NULL, false);
278 if (ret != EFI_SUCCESS)
279 goto err;
280
281 ret = efi_set_secure_state(0, 1, 1, 0);
282 if (ret != EFI_SUCCESS)
283 goto err;
284 } else if (mode == EFI_MODE_USER) {
285 ret = efi_set_secure_state(1, 0, 0, 0);
286 if (ret != EFI_SUCCESS)
287 goto err;
288 } else if (mode == EFI_MODE_SETUP) {
289 ret = efi_set_secure_state(0, 1, 0, 0);
290 if (ret != EFI_SUCCESS)
291 goto err;
292 } else {
293 return EFI_INVALID_PARAMETER;
294 }
295
296 efi_secure_mode = mode;
297
298 return EFI_SUCCESS;
299
300err:
301 /* TODO: What action should be taken here? */
302 printf("ERROR: Secure state transition failed\n");
303 return ret;
304}
305
306efi_status_t efi_init_secure_state(void)
307{
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200308 enum efi_secure_mode mode;
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200309 u8 efi_vendor_keys = 0;
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200310 efi_uintn_t size;
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200311 efi_status_t ret;
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200312 u8 deployed_mode = 0;
313 u8 audit_mode = 0;
314 u8 setup_mode = 1;
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200315
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200316 if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) {
317 size = sizeof(deployed_mode);
318 ret = efi_get_variable_int(u"DeployedMode", &efi_global_variable_guid,
319 NULL, &size, &deployed_mode, NULL);
320 size = sizeof(audit_mode);
321 ret = efi_get_variable_int(u"AuditMode", &efi_global_variable_guid,
322 NULL, &size, &audit_mode, NULL);
323 size = 0;
324 ret = efi_get_variable_int(u"PK", &efi_global_variable_guid,
325 NULL, &size, NULL, NULL);
326 if (ret == EFI_BUFFER_TOO_SMALL) {
327 setup_mode = 0;
328 audit_mode = 0;
329 } else {
330 setup_mode = 1;
331 deployed_mode = 0;
332 }
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200333 }
Heinrich Schuchardt3f65f812021-09-02 07:11:45 +0200334 if (deployed_mode)
335 mode = EFI_MODE_DEPLOYED;
336 else if (audit_mode)
337 mode = EFI_MODE_AUDIT;
338 else if (setup_mode)
339 mode = EFI_MODE_SETUP;
340 else
341 mode = EFI_MODE_USER;
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200342
343 ret = efi_transfer_secure_state(mode);
344 if (ret != EFI_SUCCESS)
345 return ret;
346
347 /* As we do not provide vendor keys this variable is always 0. */
Simon Glass90975372022-01-23 12:55:12 -0700348 ret = efi_set_variable_int(u"VendorKeys",
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200349 &efi_global_variable_guid,
350 EFI_VARIABLE_BOOTSERVICE_ACCESS |
351 EFI_VARIABLE_RUNTIME_ACCESS |
352 EFI_VARIABLE_READ_ONLY,
353 sizeof(efi_vendor_keys),
354 &efi_vendor_keys, false);
355 return ret;
356}
357
358/**
359 * efi_secure_boot_enabled - return if secure boot is enabled or not
360 *
361 * Return: true if enabled, false if disabled
362 */
363bool efi_secure_boot_enabled(void)
364{
365 return efi_secure_boot;
366}
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200367
Heinrich Schuchardt1ad2f0d2021-09-09 07:12:14 +0200368enum efi_auth_var_type efi_auth_var_get_type(const u16 *name,
369 const efi_guid_t *guid)
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200370{
371 for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
372 if (!u16_strcmp(name, name_type[i].name) &&
373 !guidcmp(guid, name_type[i].guid))
374 return name_type[i].type;
375 }
376 return EFI_AUTH_VAR_NONE;
377}
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200378
Heinrich Schuchardtcbd28022021-09-09 08:22:58 +0200379const efi_guid_t *efi_auth_var_get_guid(const u16 *name)
380{
381 for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
382 if (!u16_strcmp(name, name_type[i].name))
383 return name_type[i].guid;
384 }
385 return &efi_global_variable_guid;
386}
387
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200388/**
389 * efi_get_var() - read value of an EFI variable
390 *
391 * @name: variable name
392 * @start: vendor GUID
393 * @size: size of allocated buffer
394 *
395 * Return: buffer with variable data or NULL
396 */
Heinrich Schuchardt1ad2f0d2021-09-09 07:12:14 +0200397void *efi_get_var(const u16 *name, const efi_guid_t *vendor, efi_uintn_t *size)
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200398{
399 efi_status_t ret;
400 void *buf = NULL;
401
402 *size = 0;
403 ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
404 if (ret == EFI_BUFFER_TOO_SMALL) {
405 buf = malloc(*size);
406 if (!buf)
407 return NULL;
408 ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
409 }
410
411 if (ret != EFI_SUCCESS) {
412 free(buf);
413 *size = 0;
414 return NULL;
415 }
416
417 return buf;
418}