blob: 8ed4b0830ba162d9684c0b153d992ea49d8e64d7 [file] [log] [blame]
Tom Rini70df9d62018-05-07 17:02:21 -04001// SPDX-License-Identifier: GPL-2.0+
Rob Clark15f3d742017-09-13 18:05:37 -04002/*
Heinrich Schuchardtc69addd2020-03-19 17:15:18 +00003 * UEFI runtime variable services
Rob Clark15f3d742017-09-13 18:05:37 -04004 *
Heinrich Schuchardtc69addd2020-03-19 17:15:18 +00005 * Copyright (c) 2017 Rob Clark
Rob Clark15f3d742017-09-13 18:05:37 -04006 */
7
Heinrich Schuchardt147d5d32019-10-26 23:53:48 +02008#include <common.h>
Rob Clark15f3d742017-09-13 18:05:37 -04009#include <efi_loader.h>
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020010#include <efi_variable.h>
Simon Glassed38aef2020-05-10 11:40:03 -060011#include <env.h>
Simon Glass9d1f6192019-08-02 09:44:25 -060012#include <env_internal.h>
Heinrich Schuchardt147d5d32019-10-26 23:53:48 +020013#include <hexdump.h>
14#include <malloc.h>
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090015#include <rtc.h>
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +010016#include <search.h>
Simon Glass6f044982020-05-10 11:39:52 -060017#include <uuid.h>
AKASHI Takahiro6ec67672020-04-21 09:38:17 +090018#include <crypto/pkcs7_parser.h>
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090019#include <linux/compat.h>
Simon Glass48b6c6b2019-11-14 12:57:16 -070020#include <u-boot/crc.h>
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090021
AKASHI Takahiroc78dc192020-04-14 11:51:42 +090022enum efi_secure_mode {
23 EFI_MODE_SETUP,
24 EFI_MODE_USER,
25 EFI_MODE_AUDIT,
26 EFI_MODE_DEPLOYED,
27};
28
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090029static bool efi_secure_boot;
Heinrich Schuchardte422dcc2020-06-24 12:14:49 +020030static enum efi_secure_mode efi_secure_mode;
AKASHI Takahiro94b139a2020-04-14 11:51:43 +090031static u8 efi_vendor_keys;
Rob Clark15f3d742017-09-13 18:05:37 -040032
Rob Clark15f3d742017-09-13 18:05:37 -040033/*
34 * Mapping between EFI variables and u-boot variables:
35 *
36 * efi_$guid_$varname = {attributes}(type)value
37 *
38 * For example:
39 *
40 * efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported=
41 * "{ro,boot,run}(blob)0000000000000000"
42 * efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder=
43 * "(blob)00010000"
44 *
45 * The attributes are a comma separated list of these possible
46 * attributes:
47 *
48 * + ro - read-only
49 * + boot - boot-services access
50 * + run - runtime access
51 *
52 * NOTE: with current implementation, no variables are available after
53 * ExitBootServices, and all are persisted (if possible).
54 *
55 * If not specified, the attributes default to "{boot}".
56 *
57 * The required type is one of:
58 *
59 * + utf8 - raw utf8 string
60 * + blob - arbitrary length hex string
61 *
62 * Maybe a utf16 type would be useful to for a string value to be auto
63 * converted to utf16?
64 */
65
Heinrich Schuchardt44389cb2018-09-23 04:08:09 +020066#define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_"))
Rob Clark15f3d742017-09-13 18:05:37 -040067
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +010068/**
69 * efi_to_native() - convert the UEFI variable name and vendor GUID to U-Boot
70 * variable name
71 *
72 * The U-Boot variable name is a concatenation of prefix 'efi', the hexstring
73 * encoded vendor GUID, and the UTF-8 encoded UEFI variable name separated by
74 * underscores, e.g. 'efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder'.
75 *
76 * @native: pointer to pointer to U-Boot variable name
77 * @variable_name: UEFI variable name
78 * @vendor: vendor GUID
79 * Return: status code
80 */
Heinrich Schuchardtaf1a9202018-08-31 21:31:31 +020081static efi_status_t efi_to_native(char **native, const u16 *variable_name,
Heinrich Schuchardte06ae192018-12-30 20:53:51 +010082 const efi_guid_t *vendor)
Rob Clark15f3d742017-09-13 18:05:37 -040083{
84 size_t len;
Heinrich Schuchardtaf1a9202018-08-31 21:31:31 +020085 char *pos;
Rob Clark15f3d742017-09-13 18:05:37 -040086
Heinrich Schuchardtaf1a9202018-08-31 21:31:31 +020087 len = PREFIX_LEN + utf16_utf8_strlen(variable_name) + 1;
88 *native = malloc(len);
89 if (!*native)
90 return EFI_OUT_OF_RESOURCES;
Rob Clark15f3d742017-09-13 18:05:37 -040091
Heinrich Schuchardtaf1a9202018-08-31 21:31:31 +020092 pos = *native;
93 pos += sprintf(pos, "efi_%pUl_", vendor);
94 utf16_utf8_strcpy(&pos, variable_name);
Rob Clark15f3d742017-09-13 18:05:37 -040095
96 return EFI_SUCCESS;
97}
98
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +010099/**
100 * prefix() - skip over prefix
101 *
102 * Skip over a prefix string.
103 *
104 * @str: string with prefix
105 * @prefix: prefix string
106 * Return: string without prefix, or NULL if prefix not found
107 */
Rob Clark15f3d742017-09-13 18:05:37 -0400108static const char *prefix(const char *str, const char *prefix)
109{
110 size_t n = strlen(prefix);
111 if (!strncmp(prefix, str, n))
112 return str + n;
113 return NULL;
114}
115
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +0100116/**
117 * parse_attr() - decode attributes part of variable value
118 *
119 * Convert the string encoded attributes of a UEFI variable to a bit mask.
120 * TODO: Several attributes are not supported.
121 *
122 * @str: value of U-Boot variable
123 * @attrp: pointer to UEFI attributes
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900124 * @timep: pointer to time attribute
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +0100125 * Return: pointer to remainder of U-Boot variable value
126 */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900127static const char *parse_attr(const char *str, u32 *attrp, u64 *timep)
Rob Clark15f3d742017-09-13 18:05:37 -0400128{
129 u32 attr = 0;
130 char sep = '{';
131
132 if (*str != '{') {
133 *attrp = EFI_VARIABLE_BOOTSERVICE_ACCESS;
134 return str;
135 }
136
137 while (*str == sep) {
138 const char *s;
139
140 str++;
141
142 if ((s = prefix(str, "ro"))) {
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200143 attr |= EFI_VARIABLE_READ_ONLY;
AKASHI Takahiro7f334332019-06-04 15:52:06 +0900144 } else if ((s = prefix(str, "nv"))) {
145 attr |= EFI_VARIABLE_NON_VOLATILE;
Rob Clark15f3d742017-09-13 18:05:37 -0400146 } else if ((s = prefix(str, "boot"))) {
147 attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS;
148 } else if ((s = prefix(str, "run"))) {
149 attr |= EFI_VARIABLE_RUNTIME_ACCESS;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900150 } else if ((s = prefix(str, "time="))) {
151 attr |= EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
152 hex2bin((u8 *)timep, s, sizeof(*timep));
153 s += sizeof(*timep) * 2;
154 } else if (*str == '}') {
155 break;
Rob Clark15f3d742017-09-13 18:05:37 -0400156 } else {
157 printf("invalid attribute: %s\n", str);
158 break;
159 }
160
161 str = s;
162 sep = ',';
163 }
164
165 str++;
166
167 *attrp = attr;
168
169 return str;
170}
171
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900172/**
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900173 * efi_set_secure_state - modify secure boot state variables
Heinrich Schuchardtbae548c2020-06-24 12:38:00 +0200174 * @secure_boot: value of SecureBoot
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900175 * @setup_mode: value of SetupMode
176 * @audit_mode: value of AuditMode
177 * @deployed_mode: value of DeployedMode
178 *
Heinrich Schuchardtbae548c2020-06-24 12:38:00 +0200179 * Modify secure boot status related variables as indicated.
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900180 *
181 * Return: status code
182 */
Heinrich Schuchardtbae548c2020-06-24 12:38:00 +0200183static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode,
184 u8 audit_mode, u8 deployed_mode)
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900185{
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900186 efi_status_t ret;
Heinrich Schuchardt93f96252020-07-04 18:34:15 +0200187 const u32 attributes_ro = EFI_VARIABLE_BOOTSERVICE_ACCESS |
188 EFI_VARIABLE_RUNTIME_ACCESS |
189 EFI_VARIABLE_READ_ONLY;
190 const u32 attributes_rw = EFI_VARIABLE_BOOTSERVICE_ACCESS |
191 EFI_VARIABLE_RUNTIME_ACCESS;
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900192
Heinrich Schuchardt40fbdd82020-07-05 02:29:50 +0200193 efi_secure_boot = secure_boot;
194
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200195 ret = efi_set_variable_int(L"SecureBoot", &efi_global_variable_guid,
Heinrich Schuchardt93f96252020-07-04 18:34:15 +0200196 attributes_ro, sizeof(secure_boot),
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200197 &secure_boot, false);
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900198 if (ret != EFI_SUCCESS)
199 goto err;
200
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200201 ret = efi_set_variable_int(L"SetupMode", &efi_global_variable_guid,
Heinrich Schuchardt93f96252020-07-04 18:34:15 +0200202 attributes_ro, sizeof(setup_mode),
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200203 &setup_mode, false);
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900204 if (ret != EFI_SUCCESS)
205 goto err;
206
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200207 ret = efi_set_variable_int(L"AuditMode", &efi_global_variable_guid,
Heinrich Schuchardt93f96252020-07-04 18:34:15 +0200208 audit_mode || setup_mode ?
209 attributes_ro : attributes_rw,
210 sizeof(audit_mode), &audit_mode, false);
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900211 if (ret != EFI_SUCCESS)
212 goto err;
213
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200214 ret = efi_set_variable_int(L"DeployedMode",
Heinrich Schuchardt93f96252020-07-04 18:34:15 +0200215 &efi_global_variable_guid,
216 audit_mode || deployed_mode || setup_mode ?
217 attributes_ro : attributes_rw,
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200218 sizeof(deployed_mode), &deployed_mode,
219 false);
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900220err:
221 return ret;
222}
223
224/**
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900225 * efi_transfer_secure_state - handle a secure boot state transition
226 * @mode: new state
227 *
228 * Depending on @mode, secure boot related variables are updated.
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200229 * Those variables are *read-only* for users, efi_set_variable_int()
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900230 * is called here.
231 *
Heinrich Schuchardte2c43da2020-05-03 16:29:00 +0200232 * Return: status code
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900233 */
234static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
235{
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900236 efi_status_t ret;
237
AKASHI Takahiro37123732020-06-09 14:09:34 +0900238 EFI_PRINT("Switching secure state from %d to %d\n", efi_secure_mode,
239 mode);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900240
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900241 if (mode == EFI_MODE_DEPLOYED) {
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900242 ret = efi_set_secure_state(1, 0, 0, 1);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900243 if (ret != EFI_SUCCESS)
244 goto err;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900245 } else if (mode == EFI_MODE_AUDIT) {
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200246 ret = efi_set_variable_int(L"PK", &efi_global_variable_guid,
247 EFI_VARIABLE_BOOTSERVICE_ACCESS |
248 EFI_VARIABLE_RUNTIME_ACCESS,
249 0, NULL, false);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900250 if (ret != EFI_SUCCESS)
251 goto err;
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900252
253 ret = efi_set_secure_state(0, 1, 1, 0);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900254 if (ret != EFI_SUCCESS)
255 goto err;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900256 } else if (mode == EFI_MODE_USER) {
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900257 ret = efi_set_secure_state(1, 0, 0, 0);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900258 if (ret != EFI_SUCCESS)
259 goto err;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900260 } else if (mode == EFI_MODE_SETUP) {
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900261 ret = efi_set_secure_state(0, 1, 0, 0);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900262 if (ret != EFI_SUCCESS)
263 goto err;
264 } else {
265 return EFI_INVALID_PARAMETER;
266 }
267
AKASHI Takahiro94b139a2020-04-14 11:51:43 +0900268 efi_secure_mode = mode;
269
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900270 return EFI_SUCCESS;
271
272err:
273 /* TODO: What action should be taken here? */
274 printf("ERROR: Secure state transition failed\n");
275 return ret;
276}
277
278/**
279 * efi_init_secure_state - initialize secure boot state
280 *
Heinrich Schuchardte2c43da2020-05-03 16:29:00 +0200281 * Return: status code
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900282 */
283static efi_status_t efi_init_secure_state(void)
284{
Heinrich Schuchardt6a288f72020-07-04 22:41:26 +0200285 enum efi_secure_mode mode = EFI_MODE_SETUP;
286 efi_uintn_t size = 0;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900287 efi_status_t ret;
288
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200289 ret = efi_get_variable_int(L"PK", &efi_global_variable_guid,
290 NULL, &size, NULL, NULL);
AKASHI Takahiro94b139a2020-04-14 11:51:43 +0900291 if (ret == EFI_BUFFER_TOO_SMALL) {
292 if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT))
293 mode = EFI_MODE_USER;
AKASHI Takahiro94b139a2020-04-14 11:51:43 +0900294 }
295
296 ret = efi_transfer_secure_state(mode);
Heinrich Schuchardt6a288f72020-07-04 22:41:26 +0200297 if (ret != EFI_SUCCESS)
298 return ret;
AKASHI Takahiro94b139a2020-04-14 11:51:43 +0900299
Heinrich Schuchardt6a288f72020-07-04 22:41:26 +0200300 /* As we do not provide vendor keys this variable is always 0. */
301 ret = efi_set_variable_int(L"VendorKeys",
302 &efi_global_variable_guid,
303 EFI_VARIABLE_BOOTSERVICE_ACCESS |
304 EFI_VARIABLE_RUNTIME_ACCESS |
305 EFI_VARIABLE_READ_ONLY,
306 sizeof(efi_vendor_keys),
307 &efi_vendor_keys, false);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900308 return ret;
309}
310
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +0100311/**
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900312 * efi_secure_boot_enabled - return if secure boot is enabled or not
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +0100313 *
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900314 * Return: true if enabled, false if disabled
315 */
316bool efi_secure_boot_enabled(void)
317{
318 return efi_secure_boot;
319}
320
321#ifdef CONFIG_EFI_SECURE_BOOT
322static u8 pkcs7_hdr[] = {
323 /* SEQUENCE */
324 0x30, 0x82, 0x05, 0xc7,
325 /* OID: pkcs7-signedData */
326 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02,
327 /* Context Structured? */
328 0xa0, 0x82, 0x05, 0xb8,
329};
330
331/**
332 * efi_variable_parse_signature - parse a signature in variable
333 * @buf: Pointer to variable's value
334 * @buflen: Length of @buf
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +0100335 *
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900336 * Parse a signature embedded in variable's value and instantiate
337 * a pkcs7_message structure. Since pkcs7_parse_message() accepts only
338 * pkcs7's signedData, some header needed be prepended for correctly
339 * parsing authentication data, particularly for variable's.
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +0100340 *
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900341 * Return: Pointer to pkcs7_message structure on success, NULL on error
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +0100342 */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900343static struct pkcs7_message *efi_variable_parse_signature(const void *buf,
344 size_t buflen)
345{
346 u8 *ebuf;
347 size_t ebuflen, len;
348 struct pkcs7_message *msg;
349
350 /*
351 * This is the best assumption to check if the binary is
352 * already in a form of pkcs7's signedData.
353 */
354 if (buflen > sizeof(pkcs7_hdr) &&
355 !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) {
356 msg = pkcs7_parse_message(buf, buflen);
357 goto out;
358 }
359
360 /*
361 * Otherwise, we should add a dummy prefix sequence for pkcs7
362 * message parser to be able to process.
363 * NOTE: EDK2 also uses similar hack in WrapPkcs7Data()
364 * in CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c
365 * TODO:
366 * The header should be composed in a more refined manner.
367 */
AKASHI Takahiro37123732020-06-09 14:09:34 +0900368 EFI_PRINT("Makeshift prefix added to authentication data\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900369 ebuflen = sizeof(pkcs7_hdr) + buflen;
370 if (ebuflen <= 0x7f) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900371 EFI_PRINT("Data is too short\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900372 return NULL;
373 }
374
375 ebuf = malloc(ebuflen);
376 if (!ebuf) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900377 EFI_PRINT("Out of memory\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900378 return NULL;
379 }
380
381 memcpy(ebuf, pkcs7_hdr, sizeof(pkcs7_hdr));
382 memcpy(ebuf + sizeof(pkcs7_hdr), buf, buflen);
383 len = ebuflen - 4;
384 ebuf[2] = (len >> 8) & 0xff;
385 ebuf[3] = len & 0xff;
386 len = ebuflen - 0x13;
387 ebuf[0x11] = (len >> 8) & 0xff;
388 ebuf[0x12] = len & 0xff;
389
390 msg = pkcs7_parse_message(ebuf, ebuflen);
391
392 free(ebuf);
393
394out:
395 if (IS_ERR(msg))
396 return NULL;
397
398 return msg;
399}
400
401/**
402 * efi_variable_authenticate - authenticate a variable
403 * @variable: Variable name in u16
404 * @vendor: Guid of variable
405 * @data_size: Size of @data
406 * @data: Pointer to variable's value
407 * @given_attr: Attributes to be given at SetVariable()
408 * @env_attr: Attributes that an existing variable holds
409 * @time: signed time that an existing variable holds
410 *
411 * Called by efi_set_variable() to verify that the input is correct.
412 * Will replace the given data pointer with another that points to
413 * the actual data to store in the internal memory.
414 * On success, @data and @data_size will be replaced with variable's
415 * actual data, excluding authentication data, and its size, and variable's
416 * attributes and signed time will also be returned in @env_attr and @time,
417 * respectively.
418 *
Heinrich Schuchardte2c43da2020-05-03 16:29:00 +0200419 * Return: status code
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900420 */
421static efi_status_t efi_variable_authenticate(u16 *variable,
422 const efi_guid_t *vendor,
423 efi_uintn_t *data_size,
424 const void **data, u32 given_attr,
425 u32 *env_attr, u64 *time)
426{
427 const struct efi_variable_authentication_2 *auth;
428 struct efi_signature_store *truststore, *truststore2;
429 struct pkcs7_message *var_sig;
430 struct efi_image_regions *regs;
431 struct efi_time timestamp;
432 struct rtc_time tm;
433 u64 new_time;
434 efi_status_t ret;
435
436 var_sig = NULL;
437 truststore = NULL;
438 truststore2 = NULL;
439 regs = NULL;
440 ret = EFI_SECURITY_VIOLATION;
441
442 if (*data_size < sizeof(struct efi_variable_authentication_2))
443 goto err;
444
445 /* authentication data */
446 auth = *data;
447 if (*data_size < (sizeof(auth->time_stamp)
448 + auth->auth_info.hdr.dwLength))
449 goto err;
450
451 if (guidcmp(&auth->auth_info.cert_type, &efi_guid_cert_type_pkcs7))
452 goto err;
453
Heinrich Schuchardt7a76a3f2020-07-01 12:44:00 +0200454 memcpy(&timestamp, &auth->time_stamp, sizeof(timestamp));
455 if (timestamp.pad1 || timestamp.nanosecond || timestamp.timezone ||
456 timestamp.daylight || timestamp.pad2)
457 goto err;
458
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900459 *data += sizeof(auth->time_stamp) + auth->auth_info.hdr.dwLength;
460 *data_size -= (sizeof(auth->time_stamp)
461 + auth->auth_info.hdr.dwLength);
462
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900463 memset(&tm, 0, sizeof(tm));
464 tm.tm_year = timestamp.year;
465 tm.tm_mon = timestamp.month;
466 tm.tm_mday = timestamp.day;
467 tm.tm_hour = timestamp.hour;
468 tm.tm_min = timestamp.minute;
469 tm.tm_sec = timestamp.second;
470 new_time = rtc_mktime(&tm);
471
472 if (!efi_secure_boot_enabled()) {
473 /* finished checking */
474 *time = new_time;
475 return EFI_SUCCESS;
476 }
477
478 if (new_time <= *time)
479 goto err;
480
481 /* data to be digested */
482 regs = calloc(sizeof(*regs) + sizeof(struct image_region) * 5, 1);
483 if (!regs)
484 goto err;
485 regs->max = 5;
486 efi_image_region_add(regs, (uint8_t *)variable,
487 (uint8_t *)variable
488 + u16_strlen(variable) * sizeof(u16), 1);
489 efi_image_region_add(regs, (uint8_t *)vendor,
490 (uint8_t *)vendor + sizeof(*vendor), 1);
491 efi_image_region_add(regs, (uint8_t *)&given_attr,
492 (uint8_t *)&given_attr + sizeof(given_attr), 1);
493 efi_image_region_add(regs, (uint8_t *)&timestamp,
494 (uint8_t *)&timestamp + sizeof(timestamp), 1);
495 efi_image_region_add(regs, (uint8_t *)*data,
496 (uint8_t *)*data + *data_size, 1);
497
498 /* variable's signature list */
499 if (auth->auth_info.hdr.dwLength < sizeof(auth->auth_info))
500 goto err;
501 var_sig = efi_variable_parse_signature(auth->auth_info.cert_data,
502 auth->auth_info.hdr.dwLength
503 - sizeof(auth->auth_info));
Patrick Wildtcd8a55b2020-05-07 02:13:18 +0200504 if (!var_sig) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900505 EFI_PRINT("Parsing variable's signature failed\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900506 goto err;
507 }
508
509 /* signature database used for authentication */
510 if (u16_strcmp(variable, L"PK") == 0 ||
511 u16_strcmp(variable, L"KEK") == 0) {
512 /* with PK */
513 truststore = efi_sigstore_parse_sigdb(L"PK");
514 if (!truststore)
515 goto err;
516 } else if (u16_strcmp(variable, L"db") == 0 ||
517 u16_strcmp(variable, L"dbx") == 0) {
518 /* with PK and KEK */
519 truststore = efi_sigstore_parse_sigdb(L"KEK");
520 truststore2 = efi_sigstore_parse_sigdb(L"PK");
521
522 if (!truststore) {
523 if (!truststore2)
524 goto err;
525
526 truststore = truststore2;
527 truststore2 = NULL;
528 }
529 } else {
530 /* TODO: support private authenticated variables */
531 goto err;
532 }
533
534 /* verify signature */
535 if (efi_signature_verify_with_sigdb(regs, var_sig, truststore, NULL)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900536 EFI_PRINT("Verified\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900537 } else {
538 if (truststore2 &&
539 efi_signature_verify_with_sigdb(regs, var_sig,
540 truststore2, NULL)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900541 EFI_PRINT("Verified\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900542 } else {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900543 EFI_PRINT("Verifying variable's signature failed\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900544 goto err;
545 }
546 }
547
548 /* finished checking */
Heinrich Schuchardt5106dc72020-06-30 12:02:14 +0200549 *time = new_time;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900550 ret = EFI_SUCCESS;
551
552err:
553 efi_sigstore_free(truststore);
554 efi_sigstore_free(truststore2);
555 pkcs7_free_message(var_sig);
556 free(regs);
557
558 return ret;
559}
560#else
561static efi_status_t efi_variable_authenticate(u16 *variable,
562 const efi_guid_t *vendor,
563 efi_uintn_t *data_size,
564 const void **data, u32 given_attr,
565 u32 *env_attr, u64 *time)
566{
567 return EFI_SUCCESS;
568}
569#endif /* CONFIG_EFI_SECURE_BOOT */
570
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200571efi_status_t efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
572 u32 *attributes, efi_uintn_t *data_size,
573 void *data, u64 *timep)
Rob Clark15f3d742017-09-13 18:05:37 -0400574{
Heinrich Schuchardtaf1a9202018-08-31 21:31:31 +0200575 char *native_name;
Rob Clark15f3d742017-09-13 18:05:37 -0400576 efi_status_t ret;
577 unsigned long in_size;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900578 const char *val = NULL, *s;
579 u64 time = 0;
Rob Clark15f3d742017-09-13 18:05:37 -0400580 u32 attr;
581
Rob Clark15f3d742017-09-13 18:05:37 -0400582 if (!variable_name || !vendor || !data_size)
Heinrich Schuchardt563e5522020-06-29 11:49:58 +0200583 return EFI_INVALID_PARAMETER;
Rob Clark15f3d742017-09-13 18:05:37 -0400584
Heinrich Schuchardtaf1a9202018-08-31 21:31:31 +0200585 ret = efi_to_native(&native_name, variable_name, vendor);
Rob Clark15f3d742017-09-13 18:05:37 -0400586 if (ret)
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900587 return ret;
Rob Clark15f3d742017-09-13 18:05:37 -0400588
Heinrich Schuchardt55111c32019-04-04 21:36:44 +0200589 EFI_PRINT("get '%s'\n", native_name);
Rob Clark15f3d742017-09-13 18:05:37 -0400590
591 val = env_get(native_name);
Heinrich Schuchardtaf1a9202018-08-31 21:31:31 +0200592 free(native_name);
Rob Clark15f3d742017-09-13 18:05:37 -0400593 if (!val)
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900594 return EFI_NOT_FOUND;
Rob Clark15f3d742017-09-13 18:05:37 -0400595
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900596 val = parse_attr(val, &attr, &time);
Rob Clark15f3d742017-09-13 18:05:37 -0400597
Heinrich Schuchardt2db39ef2020-07-01 15:32:47 +0200598 if (timep)
599 *timep = time;
600
Rob Clark15f3d742017-09-13 18:05:37 -0400601 in_size = *data_size;
602
603 if ((s = prefix(val, "(blob)"))) {
Heinrich Schuchardt2d8aedc2019-01-18 12:31:54 +0100604 size_t len = strlen(s);
Rob Clark15f3d742017-09-13 18:05:37 -0400605
Ivan Gorinovd3ea6b72018-05-11 13:18:25 -0700606 /* number of hexadecimal digits must be even */
607 if (len & 1)
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900608 return EFI_DEVICE_ERROR;
Ivan Gorinovd3ea6b72018-05-11 13:18:25 -0700609
Rob Clark15f3d742017-09-13 18:05:37 -0400610 /* two characters per byte: */
Ivan Gorinovd3ea6b72018-05-11 13:18:25 -0700611 len /= 2;
Rob Clark15f3d742017-09-13 18:05:37 -0400612 *data_size = len;
613
Heinrich Schuchardt05f728f2019-05-15 19:32:43 +0200614 if (in_size < len) {
615 ret = EFI_BUFFER_TOO_SMALL;
616 goto out;
617 }
Rob Clark15f3d742017-09-13 18:05:37 -0400618
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900619 if (!data) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900620 EFI_PRINT("Variable with no data shouldn't exist.\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900621 return EFI_INVALID_PARAMETER;
622 }
Rob Clark15f3d742017-09-13 18:05:37 -0400623
Heinrich Schuchardt2d8aedc2019-01-18 12:31:54 +0100624 if (hex2bin(data, s, len))
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900625 return EFI_DEVICE_ERROR;
Rob Clark15f3d742017-09-13 18:05:37 -0400626
Heinrich Schuchardt55111c32019-04-04 21:36:44 +0200627 EFI_PRINT("got value: \"%s\"\n", s);
Rob Clark15f3d742017-09-13 18:05:37 -0400628 } else if ((s = prefix(val, "(utf8)"))) {
629 unsigned len = strlen(s) + 1;
630
631 *data_size = len;
632
Heinrich Schuchardt05f728f2019-05-15 19:32:43 +0200633 if (in_size < len) {
634 ret = EFI_BUFFER_TOO_SMALL;
635 goto out;
636 }
Rob Clark15f3d742017-09-13 18:05:37 -0400637
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900638 if (!data) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900639 EFI_PRINT("Variable with no data shouldn't exist.\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900640 return EFI_INVALID_PARAMETER;
641 }
Rob Clark15f3d742017-09-13 18:05:37 -0400642
643 memcpy(data, s, len);
644 ((char *)data)[len] = '\0';
645
Heinrich Schuchardt55111c32019-04-04 21:36:44 +0200646 EFI_PRINT("got value: \"%s\"\n", (char *)data);
Rob Clark15f3d742017-09-13 18:05:37 -0400647 } else {
Heinrich Schuchardt55111c32019-04-04 21:36:44 +0200648 EFI_PRINT("invalid value: '%s'\n", val);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900649 return EFI_DEVICE_ERROR;
Rob Clark15f3d742017-09-13 18:05:37 -0400650 }
651
Heinrich Schuchardt05f728f2019-05-15 19:32:43 +0200652out:
Rob Clark15f3d742017-09-13 18:05:37 -0400653 if (attributes)
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200654 *attributes = attr;
Rob Clark15f3d742017-09-13 18:05:37 -0400655
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900656 return ret;
657}
658
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100659static char *efi_variables_list;
660static char *efi_cur_variable;
661
662/**
663 * parse_uboot_variable() - parse a u-boot variable and get uefi-related
664 * information
665 * @variable: whole data of u-boot variable (ie. name=value)
666 * @variable_name_size: size of variable_name buffer in byte
667 * @variable_name: name of uefi variable in u16, null-terminated
668 * @vendor: vendor's guid
669 * @attributes: attributes
670 *
671 * A uefi variable is encoded into a u-boot variable as described above.
672 * This function parses such a u-boot variable and retrieve uefi-related
673 * information into respective parameters. In return, variable_name_size
674 * is the size of variable name including NULL.
675 *
676 * Return: EFI_SUCCESS if parsing is OK, EFI_NOT_FOUND when
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +0200677 * the entire variable list has been returned,
678 * otherwise non-zero status code
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100679 */
680static efi_status_t parse_uboot_variable(char *variable,
681 efi_uintn_t *variable_name_size,
682 u16 *variable_name,
683 const efi_guid_t *vendor,
684 u32 *attributes)
685{
686 char *guid, *name, *end, c;
Heinrich Schuchardt31d9b3a2020-03-20 19:04:34 +0100687 size_t name_len;
688 efi_uintn_t old_variable_name_size;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900689 u64 time;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100690 u16 *p;
691
692 guid = strchr(variable, '_');
693 if (!guid)
694 return EFI_INVALID_PARAMETER;
695 guid++;
696 name = strchr(guid, '_');
697 if (!name)
698 return EFI_INVALID_PARAMETER;
699 name++;
700 end = strchr(name, '=');
701 if (!end)
702 return EFI_INVALID_PARAMETER;
703
704 name_len = end - name;
Heinrich Schuchardt31d9b3a2020-03-20 19:04:34 +0100705 old_variable_name_size = *variable_name_size;
706 *variable_name_size = sizeof(u16) * (name_len + 1);
707 if (old_variable_name_size < *variable_name_size)
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100708 return EFI_BUFFER_TOO_SMALL;
Heinrich Schuchardt31d9b3a2020-03-20 19:04:34 +0100709
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100710 end++; /* point to value */
711
712 /* variable name */
713 p = variable_name;
714 utf8_utf16_strncpy(&p, name, name_len);
715 variable_name[name_len] = 0;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100716
717 /* guid */
718 c = *(name - 1);
719 *(name - 1) = '\0'; /* guid need be null-terminated here */
AKASHI Takahiro4854f782020-05-08 14:51:21 +0900720 if (uuid_str_to_bin(guid, (unsigned char *)vendor,
721 UUID_STR_FORMAT_GUID))
722 /* The only error would be EINVAL. */
723 return EFI_INVALID_PARAMETER;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100724 *(name - 1) = c;
725
726 /* attributes */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900727 parse_attr(end, attributes, &time);
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100728
729 return EFI_SUCCESS;
730}
731
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200732efi_status_t efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
733 u16 *variable_name,
734 efi_guid_t *vendor)
Rob Clark15f3d742017-09-13 18:05:37 -0400735{
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100736 char *native_name, *variable;
737 ssize_t name_len, list_len;
738 char regex[256];
739 char * const regexlist[] = {regex};
740 u32 attributes;
741 int i;
742 efi_status_t ret;
743
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100744 if (!variable_name_size || !variable_name || !vendor)
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200745 return EFI_INVALID_PARAMETER;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100746
747 if (variable_name[0]) {
748 /* check null-terminated string */
749 for (i = 0; i < *variable_name_size; i++)
750 if (!variable_name[i])
751 break;
752 if (i >= *variable_name_size)
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200753 return EFI_INVALID_PARAMETER;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100754
755 /* search for the last-returned variable */
756 ret = efi_to_native(&native_name, variable_name, vendor);
757 if (ret)
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200758 return ret;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100759
760 name_len = strlen(native_name);
761 for (variable = efi_variables_list; variable && *variable;) {
762 if (!strncmp(variable, native_name, name_len) &&
763 variable[name_len] == '=')
764 break;
765
766 variable = strchr(variable, '\n');
767 if (variable)
768 variable++;
769 }
770
771 free(native_name);
772 if (!(variable && *variable))
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200773 return EFI_INVALID_PARAMETER;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100774
775 /* next variable */
776 variable = strchr(variable, '\n');
777 if (variable)
778 variable++;
779 if (!(variable && *variable))
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200780 return EFI_NOT_FOUND;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100781 } else {
782 /*
783 *new search: free a list used in the previous search
784 */
785 free(efi_variables_list);
786 efi_variables_list = NULL;
787 efi_cur_variable = NULL;
788
789 snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_.*");
790 list_len = hexport_r(&env_htab, '\n',
791 H_MATCH_REGEX | H_MATCH_KEY,
792 &efi_variables_list, 0, 1, regexlist);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900793
Heinrich Schuchardtfd738482019-01-22 20:10:46 +0100794 if (list_len <= 1)
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200795 return EFI_NOT_FOUND;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100796
797 variable = efi_variables_list;
798 }
799
800 ret = parse_uboot_variable(variable, variable_name_size, variable_name,
801 vendor, &attributes);
802
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200803 return ret;
Rob Clark15f3d742017-09-13 18:05:37 -0400804}
805
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200806efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor,
807 u32 attributes, efi_uintn_t data_size,
808 const void *data, bool ro_check)
Rob Clark15f3d742017-09-13 18:05:37 -0400809{
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900810 char *native_name = NULL, *old_data = NULL, *val = NULL, *s;
811 efi_uintn_t old_size;
812 bool append, delete;
813 u64 time = 0;
Heinrich Schuchardt10bd8de2020-06-17 12:20:46 +0200814 u32 old_attr;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900815 efi_status_t ret = EFI_SUCCESS;
Rob Clark15f3d742017-09-13 18:05:37 -0400816
Heinrich Schuchardtadba3962019-06-12 23:28:42 +0200817 if (!variable_name || !*variable_name || !vendor ||
818 ((attributes & EFI_VARIABLE_RUNTIME_ACCESS) &&
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900819 !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS))) {
Heinrich Schuchardtaf1a9202018-08-31 21:31:31 +0200820 ret = EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900821 goto err;
Heinrich Schuchardtaf1a9202018-08-31 21:31:31 +0200822 }
Rob Clark15f3d742017-09-13 18:05:37 -0400823
Heinrich Schuchardtaf1a9202018-08-31 21:31:31 +0200824 ret = efi_to_native(&native_name, variable_name, vendor);
Rob Clark15f3d742017-09-13 18:05:37 -0400825 if (ret)
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900826 goto err;
Rob Clark15f3d742017-09-13 18:05:37 -0400827
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900828 /* check if a variable exists */
829 old_size = 0;
Heinrich Schuchardt10bd8de2020-06-17 12:20:46 +0200830 old_attr = 0;
831 ret = efi_get_variable_int(variable_name, vendor, &old_attr,
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200832 &old_size, NULL, &time);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900833 append = !!(attributes & EFI_VARIABLE_APPEND_WRITE);
834 attributes &= ~(u32)EFI_VARIABLE_APPEND_WRITE;
835 delete = !append && (!data_size || !attributes);
836
837 /* check attributes */
838 if (old_size) {
Heinrich Schuchardt10bd8de2020-06-17 12:20:46 +0200839 if (ro_check && (old_attr & EFI_VARIABLE_READ_ONLY)) {
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900840 ret = EFI_WRITE_PROTECTED;
841 goto err;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900842 }
843
844 /* attributes won't be changed */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900845 if (!delete &&
Heinrich Schuchardt10bd8de2020-06-17 12:20:46 +0200846 ((ro_check && old_attr != attributes) ||
847 (!ro_check && ((old_attr & ~(u32)EFI_VARIABLE_READ_ONLY)
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200848 != (attributes & ~(u32)EFI_VARIABLE_READ_ONLY))))) {
AKASHI Takahiro186b5a42019-05-24 15:59:03 +0900849 ret = EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900850 goto err;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900851 }
852 } else {
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900853 if (delete || append) {
Heinrich Schuchardt8021bbe2019-09-26 21:40:18 +0200854 /*
855 * Trying to delete or to update a non-existent
856 * variable.
857 */
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900858 ret = EFI_NOT_FOUND;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900859 goto err;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900860 }
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900861 }
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900862
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900863 if (((!u16_strcmp(variable_name, L"PK") ||
864 !u16_strcmp(variable_name, L"KEK")) &&
865 !guidcmp(vendor, &efi_global_variable_guid)) ||
866 ((!u16_strcmp(variable_name, L"db") ||
867 !u16_strcmp(variable_name, L"dbx")) &&
868 !guidcmp(vendor, &efi_guid_image_security_database))) {
869 /* authentication is mandatory */
870 if (!(attributes &
871 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900872 EFI_PRINT("%ls: AUTHENTICATED_WRITE_ACCESS required\n",
873 variable_name);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900874 ret = EFI_INVALID_PARAMETER;
875 goto err;
876 }
877 }
878
879 /* authenticate a variable */
880 if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) {
881 if (attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
882 ret = EFI_INVALID_PARAMETER;
883 goto err;
884 }
885 if (attributes &
886 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
887 ret = efi_variable_authenticate(variable_name, vendor,
888 &data_size, &data,
Heinrich Schuchardt10bd8de2020-06-17 12:20:46 +0200889 attributes, &old_attr,
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900890 &time);
891 if (ret != EFI_SUCCESS)
892 goto err;
893
894 /* last chance to check for delete */
895 if (!data_size)
896 delete = true;
897 }
898 } else {
899 if (attributes &
900 (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS |
901 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900902 EFI_PRINT("Secure boot is not configured\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900903 ret = EFI_INVALID_PARAMETER;
904 goto err;
905 }
906 }
907
908 /* delete a variable */
909 if (delete) {
910 /* !old_size case has been handled before */
911 val = NULL;
912 ret = EFI_SUCCESS;
913 goto out;
914 }
915
916 if (append) {
917 old_data = malloc(old_size);
918 if (!old_data) {
Heinrich Schuchardtebbda7b2020-05-06 01:37:25 +0200919 ret = EFI_OUT_OF_RESOURCES;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900920 goto err;
921 }
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200922 ret = efi_get_variable_int(variable_name, vendor,
Heinrich Schuchardt10bd8de2020-06-17 12:20:46 +0200923 &old_attr, &old_size, old_data, NULL);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900924 if (ret != EFI_SUCCESS)
925 goto err;
926 } else {
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900927 old_size = 0;
Rob Clark15f3d742017-09-13 18:05:37 -0400928 }
929
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900930 val = malloc(2 * old_size + 2 * data_size
931 + strlen("{ro,run,boot,nv,time=0123456701234567}(blob)")
932 + 1);
Heinrich Schuchardtbd095f52018-10-02 05:30:05 +0200933 if (!val) {
934 ret = EFI_OUT_OF_RESOURCES;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900935 goto err;
Heinrich Schuchardtbd095f52018-10-02 05:30:05 +0200936 }
Rob Clark15f3d742017-09-13 18:05:37 -0400937
938 s = val;
939
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900940 /*
941 * store attributes
942 */
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200943 attributes &= (EFI_VARIABLE_READ_ONLY |
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900944 EFI_VARIABLE_NON_VOLATILE |
AKASHI Takahiro7f334332019-06-04 15:52:06 +0900945 EFI_VARIABLE_BOOTSERVICE_ACCESS |
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900946 EFI_VARIABLE_RUNTIME_ACCESS |
947 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS);
Rob Clark15f3d742017-09-13 18:05:37 -0400948 s += sprintf(s, "{");
Heinrich Schuchardt10bd8de2020-06-17 12:20:46 +0200949 for (u32 attr_rem = attributes; attr_rem;) {
950 u32 attr = 1 << (ffs(attr_rem) - 1);
Rob Clark15f3d742017-09-13 18:05:37 -0400951
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200952 if (attr == EFI_VARIABLE_READ_ONLY) {
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900953 s += sprintf(s, "ro");
954 } else if (attr == EFI_VARIABLE_NON_VOLATILE) {
AKASHI Takahiro7f334332019-06-04 15:52:06 +0900955 s += sprintf(s, "nv");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900956 } else if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS) {
Rob Clark15f3d742017-09-13 18:05:37 -0400957 s += sprintf(s, "boot");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900958 } else if (attr == EFI_VARIABLE_RUNTIME_ACCESS) {
Rob Clark15f3d742017-09-13 18:05:37 -0400959 s += sprintf(s, "run");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900960 } else if (attr ==
961 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
962 s += sprintf(s, "time=");
963 s = bin2hex(s, (u8 *)&time, sizeof(time));
964 }
Rob Clark15f3d742017-09-13 18:05:37 -0400965
Heinrich Schuchardt10bd8de2020-06-17 12:20:46 +0200966 attr_rem &= ~attr;
967 if (attr_rem)
Rob Clark15f3d742017-09-13 18:05:37 -0400968 s += sprintf(s, ",");
969 }
970 s += sprintf(s, "}");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900971 s += sprintf(s, "(blob)");
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900972
Rob Clark15f3d742017-09-13 18:05:37 -0400973 /* store payload: */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900974 if (append)
975 s = bin2hex(s, old_data, old_size);
Heinrich Schuchardt807899d2019-01-18 18:54:26 +0100976 s = bin2hex(s, data, data_size);
Rob Clark15f3d742017-09-13 18:05:37 -0400977 *s = '\0';
978
Heinrich Schuchardt55111c32019-04-04 21:36:44 +0200979 EFI_PRINT("setting: %s=%s\n", native_name, val);
Rob Clark15f3d742017-09-13 18:05:37 -0400980
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900981out:
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900982 if (env_set(native_name, val)) {
Rob Clark15f3d742017-09-13 18:05:37 -0400983 ret = EFI_DEVICE_ERROR;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900984 } else {
Heinrich Schuchardt6a288f72020-07-04 22:41:26 +0200985 if (!u16_strcmp(variable_name, L"PK"))
986 ret = efi_init_secure_state();
987 else
AKASHI Takahiro94b139a2020-04-14 11:51:43 +0900988 ret = EFI_SUCCESS;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900989 }
Rob Clark15f3d742017-09-13 18:05:37 -0400990
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000991 /* Write non-volatile EFI variables to file */
992 if (attributes & EFI_VARIABLE_NON_VOLATILE &&
993 ret == EFI_SUCCESS && efi_obj_list_initialized == EFI_SUCCESS)
994 efi_var_to_file();
995
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900996err:
Heinrich Schuchardtaf1a9202018-08-31 21:31:31 +0200997 free(native_name);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900998 free(old_data);
Rob Clark15f3d742017-09-13 18:05:37 -0400999 free(val);
1000
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +09001001 return ret;
1002}
1003
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +02001004efi_status_t efi_query_variable_info_int(u32 attributes,
1005 u64 *maximum_variable_storage_size,
1006 u64 *remaining_variable_storage_size,
1007 u64 *maximum_variable_size)
1008{
1009 return EFI_UNSUPPORTED;
1010}
1011
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +09001012/**
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +02001013 * efi_query_variable_info_runtime() - runtime implementation of
1014 * QueryVariableInfo()
Heinrich Schuchardt9b19dae2019-06-20 12:13:05 +02001015 *
1016 * @attributes: bitmask to select variables to be
1017 * queried
1018 * @maximum_variable_storage_size: maximum size of storage area for the
1019 * selected variable types
1020 * @remaining_variable_storage_size: remaining size of storage are for the
1021 * selected variable types
1022 * @maximum_variable_size: maximum size of a variable of the
1023 * selected type
1024 * Returns: status code
1025 */
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +02001026efi_status_t __efi_runtime EFIAPI efi_query_variable_info_runtime(
Heinrich Schuchardt9b19dae2019-06-20 12:13:05 +02001027 u32 attributes,
1028 u64 *maximum_variable_storage_size,
1029 u64 *remaining_variable_storage_size,
1030 u64 *maximum_variable_size)
1031{
1032 return EFI_UNSUPPORTED;
1033}
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +02001034
1035/**
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +02001036 * efi_get_variable_runtime() - runtime implementation of GetVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +02001037 *
1038 * @variable_name: name of the variable
1039 * @vendor: vendor GUID
1040 * @attributes: attributes of the variable
1041 * @data_size: size of the buffer to which the variable value is copied
1042 * @data: buffer to which the variable value is copied
1043 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +02001044 */
1045static efi_status_t __efi_runtime EFIAPI
1046efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
1047 u32 *attributes, efi_uintn_t *data_size, void *data)
1048{
1049 return EFI_UNSUPPORTED;
1050}
1051
1052/**
1053 * efi_get_next_variable_name_runtime() - runtime implementation of
1054 * GetNextVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +02001055 *
1056 * @variable_name_size: size of variable_name buffer in byte
1057 * @variable_name: name of uefi variable's name in u16
1058 * @vendor: vendor's guid
1059 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +02001060 */
1061static efi_status_t __efi_runtime EFIAPI
1062efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
Heinrich Schuchardt82cd6c42020-03-22 18:28:20 +01001063 u16 *variable_name, efi_guid_t *vendor)
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +02001064{
1065 return EFI_UNSUPPORTED;
1066}
1067
1068/**
1069 * efi_set_variable_runtime() - runtime implementation of SetVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +02001070 *
1071 * @variable_name: name of the variable
1072 * @vendor: vendor GUID
1073 * @attributes: attributes of the variable
1074 * @data_size: size of the buffer with the variable value
1075 * @data: buffer with the variable value
1076 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +02001077 */
1078static efi_status_t __efi_runtime EFIAPI
1079efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
1080 u32 attributes, efi_uintn_t data_size,
1081 const void *data)
1082{
1083 return EFI_UNSUPPORTED;
1084}
1085
1086/**
1087 * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
1088 */
1089void efi_variables_boot_exit_notify(void)
1090{
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +00001091 /* Switch variable services functions to runtime version */
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +02001092 efi_runtime_services.get_variable = efi_get_variable_runtime;
1093 efi_runtime_services.get_next_variable_name =
1094 efi_get_next_variable_name_runtime;
1095 efi_runtime_services.set_variable = efi_set_variable_runtime;
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +02001096 efi_runtime_services.query_variable_info =
1097 efi_query_variable_info_runtime;
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +02001098 efi_update_table_header_crc32(&efi_runtime_services.hdr);
1099}
1100
1101/**
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +02001102 * efi_init_variables() - initialize variable services
1103 *
1104 * Return: status code
1105 */
1106efi_status_t efi_init_variables(void)
1107{
AKASHI Takahiroc78dc192020-04-14 11:51:42 +09001108 efi_status_t ret;
1109
1110 ret = efi_init_secure_state();
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +00001111 if (ret != EFI_SUCCESS)
1112 return ret;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +09001113
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +00001114 return efi_var_from_file();
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +02001115}