blob: b11ed91a74a47b6b045a100719eaaedc73989f3a [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
9#include <common.h>
10#include <efi_loader.h>
11#include <efi_variable.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020012#include <stdlib.h>
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020013
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +020014enum efi_secure_mode {
15 EFI_MODE_SETUP,
16 EFI_MODE_USER,
17 EFI_MODE_AUDIT,
18 EFI_MODE_DEPLOYED,
19};
20
Heinrich Schuchardt3a280332020-07-15 12:40:35 +020021struct efi_auth_var_name_type {
22 const u16 *name;
23 const efi_guid_t *guid;
24 const enum efi_auth_var_type type;
25};
26
27static const struct efi_auth_var_name_type name_type[] = {
28 {u"PK", &efi_global_variable_guid, EFI_AUTH_VAR_PK},
29 {u"KEK", &efi_global_variable_guid, EFI_AUTH_VAR_KEK},
30 {u"db", &efi_guid_image_security_database, EFI_AUTH_VAR_DB},
31 {u"dbx", &efi_guid_image_security_database, EFI_AUTH_VAR_DBX},
32 /* not used yet
33 {u"dbt", &efi_guid_image_security_database, EFI_AUTH_VAR_DBT},
34 {u"dbr", &efi_guid_image_security_database, EFI_AUTH_VAR_DBR},
35 */
36};
37
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +020038static bool efi_secure_boot;
39static enum efi_secure_mode efi_secure_mode;
40
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020041/**
42 * efi_efi_get_variable() - retrieve value of a UEFI variable
43 *
44 * This function implements the GetVariable runtime service.
45 *
46 * See the Unified Extensible Firmware Interface (UEFI) specification for
47 * details.
48 *
49 * @variable_name: name of the variable
50 * @vendor: vendor GUID
51 * @attributes: attributes of the variable
52 * @data_size: size of the buffer to which the variable value is copied
53 * @data: buffer to which the variable value is copied
54 * Return: status code
55 */
56efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
57 const efi_guid_t *vendor, u32 *attributes,
58 efi_uintn_t *data_size, void *data)
59{
60 efi_status_t ret;
61
62 EFI_ENTRY("\"%ls\" %pUl %p %p %p", variable_name, vendor, attributes,
63 data_size, data);
64
65 ret = efi_get_variable_int(variable_name, vendor, attributes,
66 data_size, data, NULL);
67
68 /* Remove EFI_VARIABLE_READ_ONLY flag */
69 if (attributes)
70 *attributes &= EFI_VARIABLE_MASK;
71
72 return EFI_EXIT(ret);
73}
74
75/**
76 * efi_set_variable() - set value of a UEFI variable
77 *
78 * This function implements the SetVariable runtime service.
79 *
80 * See the Unified Extensible Firmware Interface (UEFI) specification for
81 * details.
82 *
83 * @variable_name: name of the variable
84 * @vendor: vendor GUID
85 * @attributes: attributes of the variable
86 * @data_size: size of the buffer with the variable value
87 * @data: buffer with the variable value
88 * Return: status code
89 */
90efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
91 const efi_guid_t *vendor, u32 attributes,
92 efi_uintn_t data_size, const void *data)
93{
94 efi_status_t ret;
95
96 EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes,
97 data_size, data);
98
99 /* Make sure that the EFI_VARIABLE_READ_ONLY flag is not set */
100 if (attributes & ~(u32)EFI_VARIABLE_MASK)
101 ret = EFI_INVALID_PARAMETER;
102 else
103 ret = efi_set_variable_int(variable_name, vendor, attributes,
104 data_size, data, true);
105
106 return EFI_EXIT(ret);
107}
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200108
109/**
110 * efi_get_next_variable_name() - enumerate the current variable names
111 *
112 * @variable_name_size: size of variable_name buffer in byte
113 * @variable_name: name of uefi variable's name in u16
114 * @vendor: vendor's guid
115 *
116 * See the Unified Extensible Firmware Interface (UEFI) specification for
117 * details.
118 *
119 * Return: status code
120 */
121efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size,
122 u16 *variable_name,
123 efi_guid_t *vendor)
124{
125 efi_status_t ret;
126
127 EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, vendor);
128
129 ret = efi_get_next_variable_name_int(variable_name_size, variable_name,
130 vendor);
131
132 return EFI_EXIT(ret);
133}
134
135/**
136 * efi_query_variable_info() - get information about EFI variables
137 *
138 * This function implements the QueryVariableInfo() runtime service.
139 *
140 * See the Unified Extensible Firmware Interface (UEFI) specification for
141 * details.
142 *
143 * @attributes: bitmask to select variables to be
144 * queried
145 * @maximum_variable_storage_size: maximum size of storage area for the
146 * selected variable types
147 * @remaining_variable_storage_size: remaining size of storage are for the
148 * selected variable types
149 * @maximum_variable_size: maximum size of a variable of the
150 * selected type
151 * Returns: status code
152 */
153efi_status_t EFIAPI efi_query_variable_info(
154 u32 attributes, u64 *maximum_variable_storage_size,
155 u64 *remaining_variable_storage_size,
156 u64 *maximum_variable_size)
157{
158 efi_status_t ret;
159
160 EFI_ENTRY("%x %p %p %p", attributes, maximum_variable_storage_size,
161 remaining_variable_storage_size, maximum_variable_size);
162
163 ret = efi_query_variable_info_int(attributes,
164 maximum_variable_storage_size,
165 remaining_variable_storage_size,
166 maximum_variable_size);
167
168 return EFI_EXIT(ret);
169}
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200170
Ilias Apalodimasa4d1b1b2020-07-23 15:49:49 +0300171efi_status_t __efi_runtime EFIAPI
172efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
173 u32 *attributes, efi_uintn_t *data_size, void *data)
174{
175 efi_status_t ret;
176
177 ret = efi_get_variable_mem(variable_name, guid, attributes, data_size, data, NULL);
178
179 /* Remove EFI_VARIABLE_READ_ONLY flag */
180 if (attributes)
181 *attributes &= EFI_VARIABLE_MASK;
182
183 return ret;
184}
185
186efi_status_t __efi_runtime EFIAPI
187efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
188 u16 *variable_name, efi_guid_t *guid)
189{
190 return efi_get_next_variable_name_mem(variable_name_size, variable_name, guid);
191}
192
Heinrich Schuchardt0f2c3332020-07-14 08:04:49 +0200193/**
194 * efi_set_secure_state - modify secure boot state variables
195 * @secure_boot: value of SecureBoot
196 * @setup_mode: value of SetupMode
197 * @audit_mode: value of AuditMode
198 * @deployed_mode: value of DeployedMode
199 *
200 * Modify secure boot status related variables as indicated.
201 *
202 * Return: status code
203 */
204static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode,
205 u8 audit_mode, u8 deployed_mode)
206{
207 efi_status_t ret;
208 const u32 attributes_ro = EFI_VARIABLE_BOOTSERVICE_ACCESS |
209 EFI_VARIABLE_RUNTIME_ACCESS |
210 EFI_VARIABLE_READ_ONLY;
211 const u32 attributes_rw = EFI_VARIABLE_BOOTSERVICE_ACCESS |
212 EFI_VARIABLE_RUNTIME_ACCESS;
213
214 efi_secure_boot = secure_boot;
215
216 ret = efi_set_variable_int(L"SecureBoot", &efi_global_variable_guid,
217 attributes_ro, sizeof(secure_boot),
218 &secure_boot, false);
219 if (ret != EFI_SUCCESS)
220 goto err;
221
222 ret = efi_set_variable_int(L"SetupMode", &efi_global_variable_guid,
223 attributes_ro, sizeof(setup_mode),
224 &setup_mode, false);
225 if (ret != EFI_SUCCESS)
226 goto err;
227
228 ret = efi_set_variable_int(L"AuditMode", &efi_global_variable_guid,
229 audit_mode || setup_mode ?
230 attributes_ro : attributes_rw,
231 sizeof(audit_mode), &audit_mode, false);
232 if (ret != EFI_SUCCESS)
233 goto err;
234
235 ret = efi_set_variable_int(L"DeployedMode",
236 &efi_global_variable_guid,
237 audit_mode || deployed_mode || setup_mode ?
238 attributes_ro : attributes_rw,
239 sizeof(deployed_mode), &deployed_mode,
240 false);
241err:
242 return ret;
243}
244
245/**
246 * efi_transfer_secure_state - handle a secure boot state transition
247 * @mode: new state
248 *
249 * Depending on @mode, secure boot related variables are updated.
250 * Those variables are *read-only* for users, efi_set_variable_int()
251 * is called here.
252 *
253 * Return: status code
254 */
255static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
256{
257 efi_status_t ret;
258
259 EFI_PRINT("Switching secure state from %d to %d\n", efi_secure_mode,
260 mode);
261
262 if (mode == EFI_MODE_DEPLOYED) {
263 ret = efi_set_secure_state(1, 0, 0, 1);
264 if (ret != EFI_SUCCESS)
265 goto err;
266 } else if (mode == EFI_MODE_AUDIT) {
267 ret = efi_set_variable_int(L"PK", &efi_global_variable_guid,
268 EFI_VARIABLE_BOOTSERVICE_ACCESS |
269 EFI_VARIABLE_RUNTIME_ACCESS,
270 0, NULL, false);
271 if (ret != EFI_SUCCESS)
272 goto err;
273
274 ret = efi_set_secure_state(0, 1, 1, 0);
275 if (ret != EFI_SUCCESS)
276 goto err;
277 } else if (mode == EFI_MODE_USER) {
278 ret = efi_set_secure_state(1, 0, 0, 0);
279 if (ret != EFI_SUCCESS)
280 goto err;
281 } else if (mode == EFI_MODE_SETUP) {
282 ret = efi_set_secure_state(0, 1, 0, 0);
283 if (ret != EFI_SUCCESS)
284 goto err;
285 } else {
286 return EFI_INVALID_PARAMETER;
287 }
288
289 efi_secure_mode = mode;
290
291 return EFI_SUCCESS;
292
293err:
294 /* TODO: What action should be taken here? */
295 printf("ERROR: Secure state transition failed\n");
296 return ret;
297}
298
299efi_status_t efi_init_secure_state(void)
300{
301 enum efi_secure_mode mode = EFI_MODE_SETUP;
302 u8 efi_vendor_keys = 0;
303 efi_uintn_t size = 0;
304 efi_status_t ret;
305
306 ret = efi_get_variable_int(L"PK", &efi_global_variable_guid,
307 NULL, &size, NULL, NULL);
308 if (ret == EFI_BUFFER_TOO_SMALL) {
309 if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT))
310 mode = EFI_MODE_USER;
311 }
312
313 ret = efi_transfer_secure_state(mode);
314 if (ret != EFI_SUCCESS)
315 return ret;
316
317 /* As we do not provide vendor keys this variable is always 0. */
318 ret = efi_set_variable_int(L"VendorKeys",
319 &efi_global_variable_guid,
320 EFI_VARIABLE_BOOTSERVICE_ACCESS |
321 EFI_VARIABLE_RUNTIME_ACCESS |
322 EFI_VARIABLE_READ_ONLY,
323 sizeof(efi_vendor_keys),
324 &efi_vendor_keys, false);
325 return ret;
326}
327
328/**
329 * efi_secure_boot_enabled - return if secure boot is enabled or not
330 *
331 * Return: true if enabled, false if disabled
332 */
333bool efi_secure_boot_enabled(void)
334{
335 return efi_secure_boot;
336}
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200337
338enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid)
339{
340 for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
341 if (!u16_strcmp(name, name_type[i].name) &&
342 !guidcmp(guid, name_type[i].guid))
343 return name_type[i].type;
344 }
345 return EFI_AUTH_VAR_NONE;
346}
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200347
348/**
349 * efi_get_var() - read value of an EFI variable
350 *
351 * @name: variable name
352 * @start: vendor GUID
353 * @size: size of allocated buffer
354 *
355 * Return: buffer with variable data or NULL
356 */
357void *efi_get_var(u16 *name, const efi_guid_t *vendor, efi_uintn_t *size)
358{
359 efi_status_t ret;
360 void *buf = NULL;
361
362 *size = 0;
363 ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
364 if (ret == EFI_BUFFER_TOO_SMALL) {
365 buf = malloc(*size);
366 if (!buf)
367 return NULL;
368 ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
369 }
370
371 if (ret != EFI_SUCCESS) {
372 free(buf);
373 *size = 0;
374 return NULL;
375 }
376
377 return buf;
378}