blob: 39a848290380f53410d515ff30a36a250c5f15bc [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 Schuchardt4b7d5c12020-07-14 21:25:28 +02008#define LOG_CATEGORY LOGC_EFI
9
Heinrich Schuchardt147d5d32019-10-26 23:53:48 +020010#include <common.h>
Rob Clark15f3d742017-09-13 18:05:37 -040011#include <efi_loader.h>
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020012#include <efi_variable.h>
Simon Glassed38aef2020-05-10 11:40:03 -060013#include <env.h>
Simon Glass9d1f6192019-08-02 09:44:25 -060014#include <env_internal.h>
Heinrich Schuchardt147d5d32019-10-26 23:53:48 +020015#include <hexdump.h>
Heinrich Schuchardt4b7d5c12020-07-14 21:25:28 +020016#include <log.h>
Heinrich Schuchardt147d5d32019-10-26 23:53:48 +020017#include <malloc.h>
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090018#include <rtc.h>
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +010019#include <search.h>
Simon Glass6f044982020-05-10 11:39:52 -060020#include <uuid.h>
AKASHI Takahiro6ec67672020-04-21 09:38:17 +090021#include <crypto/pkcs7_parser.h>
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090022#include <linux/compat.h>
Simon Glass48b6c6b2019-11-14 12:57:16 -070023#include <u-boot/crc.h>
Heinrich Schuchardt4b7d5c12020-07-14 21:25:28 +020024#include <asm/sections.h>
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090025
26#ifdef CONFIG_EFI_SECURE_BOOT
27static u8 pkcs7_hdr[] = {
28 /* SEQUENCE */
29 0x30, 0x82, 0x05, 0xc7,
30 /* OID: pkcs7-signedData */
31 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02,
32 /* Context Structured? */
33 0xa0, 0x82, 0x05, 0xb8,
34};
35
36/**
37 * efi_variable_parse_signature - parse a signature in variable
38 * @buf: Pointer to variable's value
39 * @buflen: Length of @buf
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +010040 *
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090041 * Parse a signature embedded in variable's value and instantiate
42 * a pkcs7_message structure. Since pkcs7_parse_message() accepts only
43 * pkcs7's signedData, some header needed be prepended for correctly
44 * parsing authentication data, particularly for variable's.
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +010045 *
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090046 * Return: Pointer to pkcs7_message structure on success, NULL on error
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +010047 */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090048static struct pkcs7_message *efi_variable_parse_signature(const void *buf,
49 size_t buflen)
50{
51 u8 *ebuf;
52 size_t ebuflen, len;
53 struct pkcs7_message *msg;
54
55 /*
56 * This is the best assumption to check if the binary is
57 * already in a form of pkcs7's signedData.
58 */
59 if (buflen > sizeof(pkcs7_hdr) &&
60 !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) {
61 msg = pkcs7_parse_message(buf, buflen);
62 goto out;
63 }
64
65 /*
66 * Otherwise, we should add a dummy prefix sequence for pkcs7
67 * message parser to be able to process.
68 * NOTE: EDK2 also uses similar hack in WrapPkcs7Data()
69 * in CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c
70 * TODO:
71 * The header should be composed in a more refined manner.
72 */
AKASHI Takahiro37123732020-06-09 14:09:34 +090073 EFI_PRINT("Makeshift prefix added to authentication data\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090074 ebuflen = sizeof(pkcs7_hdr) + buflen;
75 if (ebuflen <= 0x7f) {
AKASHI Takahiro37123732020-06-09 14:09:34 +090076 EFI_PRINT("Data is too short\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090077 return NULL;
78 }
79
80 ebuf = malloc(ebuflen);
81 if (!ebuf) {
AKASHI Takahiro37123732020-06-09 14:09:34 +090082 EFI_PRINT("Out of memory\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090083 return NULL;
84 }
85
86 memcpy(ebuf, pkcs7_hdr, sizeof(pkcs7_hdr));
87 memcpy(ebuf + sizeof(pkcs7_hdr), buf, buflen);
88 len = ebuflen - 4;
89 ebuf[2] = (len >> 8) & 0xff;
90 ebuf[3] = len & 0xff;
91 len = ebuflen - 0x13;
92 ebuf[0x11] = (len >> 8) & 0xff;
93 ebuf[0x12] = len & 0xff;
94
95 msg = pkcs7_parse_message(ebuf, ebuflen);
96
97 free(ebuf);
98
99out:
100 if (IS_ERR(msg))
101 return NULL;
102
103 return msg;
104}
105
106/**
107 * efi_variable_authenticate - authenticate a variable
108 * @variable: Variable name in u16
109 * @vendor: Guid of variable
110 * @data_size: Size of @data
111 * @data: Pointer to variable's value
112 * @given_attr: Attributes to be given at SetVariable()
113 * @env_attr: Attributes that an existing variable holds
114 * @time: signed time that an existing variable holds
115 *
116 * Called by efi_set_variable() to verify that the input is correct.
117 * Will replace the given data pointer with another that points to
118 * the actual data to store in the internal memory.
119 * On success, @data and @data_size will be replaced with variable's
120 * actual data, excluding authentication data, and its size, and variable's
121 * attributes and signed time will also be returned in @env_attr and @time,
122 * respectively.
123 *
Heinrich Schuchardte2c43da2020-05-03 16:29:00 +0200124 * Return: status code
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900125 */
126static efi_status_t efi_variable_authenticate(u16 *variable,
127 const efi_guid_t *vendor,
128 efi_uintn_t *data_size,
129 const void **data, u32 given_attr,
130 u32 *env_attr, u64 *time)
131{
132 const struct efi_variable_authentication_2 *auth;
133 struct efi_signature_store *truststore, *truststore2;
134 struct pkcs7_message *var_sig;
135 struct efi_image_regions *regs;
136 struct efi_time timestamp;
137 struct rtc_time tm;
138 u64 new_time;
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200139 enum efi_auth_var_type var_type;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900140 efi_status_t ret;
141
142 var_sig = NULL;
143 truststore = NULL;
144 truststore2 = NULL;
145 regs = NULL;
146 ret = EFI_SECURITY_VIOLATION;
147
148 if (*data_size < sizeof(struct efi_variable_authentication_2))
149 goto err;
150
151 /* authentication data */
152 auth = *data;
153 if (*data_size < (sizeof(auth->time_stamp)
154 + auth->auth_info.hdr.dwLength))
155 goto err;
156
157 if (guidcmp(&auth->auth_info.cert_type, &efi_guid_cert_type_pkcs7))
158 goto err;
159
Heinrich Schuchardt7a76a3f2020-07-01 12:44:00 +0200160 memcpy(&timestamp, &auth->time_stamp, sizeof(timestamp));
161 if (timestamp.pad1 || timestamp.nanosecond || timestamp.timezone ||
162 timestamp.daylight || timestamp.pad2)
163 goto err;
164
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900165 *data += sizeof(auth->time_stamp) + auth->auth_info.hdr.dwLength;
166 *data_size -= (sizeof(auth->time_stamp)
167 + auth->auth_info.hdr.dwLength);
168
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900169 memset(&tm, 0, sizeof(tm));
170 tm.tm_year = timestamp.year;
171 tm.tm_mon = timestamp.month;
172 tm.tm_mday = timestamp.day;
173 tm.tm_hour = timestamp.hour;
174 tm.tm_min = timestamp.minute;
175 tm.tm_sec = timestamp.second;
176 new_time = rtc_mktime(&tm);
177
178 if (!efi_secure_boot_enabled()) {
179 /* finished checking */
180 *time = new_time;
181 return EFI_SUCCESS;
182 }
183
184 if (new_time <= *time)
185 goto err;
186
187 /* data to be digested */
188 regs = calloc(sizeof(*regs) + sizeof(struct image_region) * 5, 1);
189 if (!regs)
190 goto err;
191 regs->max = 5;
192 efi_image_region_add(regs, (uint8_t *)variable,
193 (uint8_t *)variable
194 + u16_strlen(variable) * sizeof(u16), 1);
195 efi_image_region_add(regs, (uint8_t *)vendor,
196 (uint8_t *)vendor + sizeof(*vendor), 1);
197 efi_image_region_add(regs, (uint8_t *)&given_attr,
198 (uint8_t *)&given_attr + sizeof(given_attr), 1);
199 efi_image_region_add(regs, (uint8_t *)&timestamp,
200 (uint8_t *)&timestamp + sizeof(timestamp), 1);
201 efi_image_region_add(regs, (uint8_t *)*data,
202 (uint8_t *)*data + *data_size, 1);
203
204 /* variable's signature list */
205 if (auth->auth_info.hdr.dwLength < sizeof(auth->auth_info))
206 goto err;
207 var_sig = efi_variable_parse_signature(auth->auth_info.cert_data,
208 auth->auth_info.hdr.dwLength
209 - sizeof(auth->auth_info));
Patrick Wildtcd8a55b2020-05-07 02:13:18 +0200210 if (!var_sig) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900211 EFI_PRINT("Parsing variable's signature failed\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900212 goto err;
213 }
214
215 /* signature database used for authentication */
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200216 var_type = efi_auth_var_get_type(variable, vendor);
217 switch (var_type) {
218 case EFI_AUTH_VAR_PK:
219 case EFI_AUTH_VAR_KEK:
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900220 /* with PK */
221 truststore = efi_sigstore_parse_sigdb(L"PK");
222 if (!truststore)
223 goto err;
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200224 break;
225 case EFI_AUTH_VAR_DB:
226 case EFI_AUTH_VAR_DBX:
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900227 /* with PK and KEK */
228 truststore = efi_sigstore_parse_sigdb(L"KEK");
229 truststore2 = efi_sigstore_parse_sigdb(L"PK");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900230 if (!truststore) {
231 if (!truststore2)
232 goto err;
233
234 truststore = truststore2;
235 truststore2 = NULL;
236 }
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200237 break;
238 default:
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900239 /* TODO: support private authenticated variables */
240 goto err;
241 }
242
243 /* verify signature */
244 if (efi_signature_verify_with_sigdb(regs, var_sig, truststore, NULL)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900245 EFI_PRINT("Verified\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900246 } else {
247 if (truststore2 &&
248 efi_signature_verify_with_sigdb(regs, var_sig,
249 truststore2, NULL)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900250 EFI_PRINT("Verified\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900251 } else {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900252 EFI_PRINT("Verifying variable's signature failed\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900253 goto err;
254 }
255 }
256
257 /* finished checking */
Heinrich Schuchardt5106dc72020-06-30 12:02:14 +0200258 *time = new_time;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900259 ret = EFI_SUCCESS;
260
261err:
262 efi_sigstore_free(truststore);
263 efi_sigstore_free(truststore2);
264 pkcs7_free_message(var_sig);
265 free(regs);
266
267 return ret;
268}
269#else
270static efi_status_t efi_variable_authenticate(u16 *variable,
271 const efi_guid_t *vendor,
272 efi_uintn_t *data_size,
273 const void **data, u32 given_attr,
274 u32 *env_attr, u64 *time)
275{
276 return EFI_SUCCESS;
277}
278#endif /* CONFIG_EFI_SECURE_BOOT */
279
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200280efi_status_t __efi_runtime
281efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
282 u32 *attributes, efi_uintn_t *data_size, void *data,
283 u64 *timep)
Rob Clark15f3d742017-09-13 18:05:37 -0400284{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200285 efi_uintn_t old_size;
286 struct efi_var_entry *var;
287 u16 *pdata;
Rob Clark15f3d742017-09-13 18:05:37 -0400288
Rob Clark15f3d742017-09-13 18:05:37 -0400289 if (!variable_name || !vendor || !data_size)
Heinrich Schuchardt563e5522020-06-29 11:49:58 +0200290 return EFI_INVALID_PARAMETER;
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200291 var = efi_var_mem_find(vendor, variable_name, NULL);
292 if (!var)
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900293 return EFI_NOT_FOUND;
Rob Clark15f3d742017-09-13 18:05:37 -0400294
Rob Clark15f3d742017-09-13 18:05:37 -0400295 if (attributes)
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200296 *attributes = var->attr;
297 if (timep)
298 *timep = var->time;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100299
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200300 old_size = *data_size;
301 *data_size = var->length;
302 if (old_size < var->length)
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100303 return EFI_BUFFER_TOO_SMALL;
Heinrich Schuchardt31d9b3a2020-03-20 19:04:34 +0100304
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200305 if (!data)
AKASHI Takahiro4854f782020-05-08 14:51:21 +0900306 return EFI_INVALID_PARAMETER;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100307
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200308 for (pdata = var->name; *pdata; ++pdata)
309 ;
310 ++pdata;
311
312 efi_memcpy_runtime(data, pdata, var->length);
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100313
314 return EFI_SUCCESS;
315}
316
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200317efi_status_t __efi_runtime
318efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
319 u16 *variable_name, efi_guid_t *vendor)
Rob Clark15f3d742017-09-13 18:05:37 -0400320{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200321 struct efi_var_entry *var;
322 efi_uintn_t old_size;
323 u16 *pdata;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100324
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100325 if (!variable_name_size || !variable_name || !vendor)
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200326 return EFI_INVALID_PARAMETER;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100327
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200328 efi_var_mem_find(vendor, variable_name, &var);
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100329
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200330 if (!var)
331 return EFI_NOT_FOUND;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100332
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200333 for (pdata = var->name; *pdata; ++pdata)
334 ;
335 ++pdata;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900336
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200337 old_size = *variable_name_size;
338 *variable_name_size = (uintptr_t)pdata - (uintptr_t)var->name;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100339
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200340 if (old_size < *variable_name_size)
341 return EFI_BUFFER_TOO_SMALL;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100342
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200343 efi_memcpy_runtime(variable_name, var->name, *variable_name_size);
344 efi_memcpy_runtime(vendor, &var->guid, sizeof(efi_guid_t));
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100345
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200346 return EFI_SUCCESS;
Rob Clark15f3d742017-09-13 18:05:37 -0400347}
348
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200349efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor,
350 u32 attributes, efi_uintn_t data_size,
351 const void *data, bool ro_check)
Rob Clark15f3d742017-09-13 18:05:37 -0400352{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200353 struct efi_var_entry *var;
354 efi_uintn_t ret;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900355 bool append, delete;
356 u64 time = 0;
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200357 enum efi_auth_var_type var_type;
Rob Clark15f3d742017-09-13 18:05:37 -0400358
Heinrich Schuchardtadba3962019-06-12 23:28:42 +0200359 if (!variable_name || !*variable_name || !vendor ||
360 ((attributes & EFI_VARIABLE_RUNTIME_ACCESS) &&
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200361 !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)))
362 return EFI_INVALID_PARAMETER;
Rob Clark15f3d742017-09-13 18:05:37 -0400363
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900364 /* check if a variable exists */
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200365 var = efi_var_mem_find(vendor, variable_name, NULL);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900366 append = !!(attributes & EFI_VARIABLE_APPEND_WRITE);
367 attributes &= ~(u32)EFI_VARIABLE_APPEND_WRITE;
368 delete = !append && (!data_size || !attributes);
369
370 /* check attributes */
Heinrich Schuchardt4b7d5c12020-07-14 21:25:28 +0200371 var_type = efi_auth_var_get_type(variable_name, vendor);
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200372 if (var) {
373 if (ro_check && (var->attr & EFI_VARIABLE_READ_ONLY))
374 return EFI_WRITE_PROTECTED;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900375
Heinrich Schuchardt4b7d5c12020-07-14 21:25:28 +0200376 if (IS_ENABLED(CONFIG_EFI_VARIABLES_PRESEED)) {
377 if (var_type != EFI_AUTH_VAR_NONE)
378 return EFI_WRITE_PROTECTED;
379 }
380
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900381 /* attributes won't be changed */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900382 if (!delete &&
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200383 ((ro_check && var->attr != attributes) ||
384 (!ro_check && ((var->attr & ~(u32)EFI_VARIABLE_READ_ONLY)
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200385 != (attributes & ~(u32)EFI_VARIABLE_READ_ONLY))))) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200386 return EFI_INVALID_PARAMETER;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900387 }
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200388 time = var->time;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900389 } else {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200390 if (delete || append)
Heinrich Schuchardt8021bbe2019-09-26 21:40:18 +0200391 /*
392 * Trying to delete or to update a non-existent
393 * variable.
394 */
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200395 return EFI_NOT_FOUND;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900396 }
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900397
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200398 if (var_type != EFI_AUTH_VAR_NONE) {
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900399 /* authentication is mandatory */
400 if (!(attributes &
401 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200402 EFI_PRINT("%ls: TIME_BASED_AUTHENTICATED_WRITE_ACCESS required\n",
AKASHI Takahiro37123732020-06-09 14:09:34 +0900403 variable_name);
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200404 return EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900405 }
406 }
407
408 /* authenticate a variable */
409 if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200410 if (attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
411 return EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900412 if (attributes &
413 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200414 u32 env_attr;
415
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900416 ret = efi_variable_authenticate(variable_name, vendor,
417 &data_size, &data,
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200418 attributes, &env_attr,
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900419 &time);
420 if (ret != EFI_SUCCESS)
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200421 return ret;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900422
423 /* last chance to check for delete */
424 if (!data_size)
425 delete = true;
426 }
427 } else {
428 if (attributes &
429 (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS |
430 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900431 EFI_PRINT("Secure boot is not configured\n");
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200432 return EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900433 }
434 }
435
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900436 if (delete) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200437 /* EFI_NOT_FOUND has been handled before */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900438 ret = EFI_SUCCESS;
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200439 } else if (append) {
440 u16 *old_data = var->name;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900441
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200442 for (; *old_data; ++old_data)
443 ;
444 ++old_data;
445 ret = efi_var_mem_ins(variable_name, vendor, attributes,
446 var->length, old_data, data_size, data,
447 time);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900448 } else {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200449 ret = efi_var_mem_ins(variable_name, vendor, attributes,
450 data_size, data, 0, NULL, time);
Rob Clark15f3d742017-09-13 18:05:37 -0400451 }
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200452 efi_var_mem_del(var);
Rob Clark15f3d742017-09-13 18:05:37 -0400453
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200454 if (ret != EFI_SUCCESS)
455 return ret;
Rob Clark15f3d742017-09-13 18:05:37 -0400456
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200457 if (var_type == EFI_AUTH_VAR_PK)
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200458 ret = efi_init_secure_state();
459 else
460 ret = EFI_SUCCESS;
Rob Clark15f3d742017-09-13 18:05:37 -0400461
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000462 /* Write non-volatile EFI variables to file */
463 if (attributes & EFI_VARIABLE_NON_VOLATILE &&
464 ret == EFI_SUCCESS && efi_obj_list_initialized == EFI_SUCCESS)
465 efi_var_to_file();
466
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200467 return EFI_SUCCESS;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900468}
469
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200470efi_status_t efi_query_variable_info_int(u32 attributes,
471 u64 *maximum_variable_storage_size,
472 u64 *remaining_variable_storage_size,
473 u64 *maximum_variable_size)
474{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200475 *maximum_variable_storage_size = EFI_VAR_BUF_SIZE -
476 sizeof(struct efi_var_file);
477 *remaining_variable_storage_size = efi_var_mem_free();
478 *maximum_variable_size = EFI_VAR_BUF_SIZE -
479 sizeof(struct efi_var_file) -
480 sizeof(struct efi_var_entry);
481 return EFI_SUCCESS;
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200482}
483
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900484/**
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200485 * efi_query_variable_info_runtime() - runtime implementation of
486 * QueryVariableInfo()
Heinrich Schuchardt9b19dae2019-06-20 12:13:05 +0200487 *
488 * @attributes: bitmask to select variables to be
489 * queried
490 * @maximum_variable_storage_size: maximum size of storage area for the
491 * selected variable types
492 * @remaining_variable_storage_size: remaining size of storage are for the
493 * selected variable types
494 * @maximum_variable_size: maximum size of a variable of the
495 * selected type
496 * Returns: status code
497 */
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200498efi_status_t __efi_runtime EFIAPI efi_query_variable_info_runtime(
Heinrich Schuchardt9b19dae2019-06-20 12:13:05 +0200499 u32 attributes,
500 u64 *maximum_variable_storage_size,
501 u64 *remaining_variable_storage_size,
502 u64 *maximum_variable_size)
503{
504 return EFI_UNSUPPORTED;
505}
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +0200506
507/**
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200508 * efi_get_variable_runtime() - runtime implementation of GetVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +0200509 *
510 * @variable_name: name of the variable
511 * @vendor: vendor GUID
512 * @attributes: attributes of the variable
513 * @data_size: size of the buffer to which the variable value is copied
514 * @data: buffer to which the variable value is copied
515 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200516 */
517static efi_status_t __efi_runtime EFIAPI
518efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
519 u32 *attributes, efi_uintn_t *data_size, void *data)
520{
Heinrich Schuchardt5be59712020-03-24 19:54:53 +0000521 efi_status_t ret;
522
523 ret = efi_get_variable_int(variable_name, vendor, attributes,
524 data_size, data, NULL);
525
526 /* Remove EFI_VARIABLE_READ_ONLY flag */
527 if (attributes)
528 *attributes &= EFI_VARIABLE_MASK;
529
530 return ret;
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200531}
532
533/**
534 * efi_get_next_variable_name_runtime() - runtime implementation of
535 * GetNextVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +0200536 *
537 * @variable_name_size: size of variable_name buffer in byte
538 * @variable_name: name of uefi variable's name in u16
539 * @vendor: vendor's guid
540 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200541 */
542static efi_status_t __efi_runtime EFIAPI
543efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
Heinrich Schuchardt82cd6c42020-03-22 18:28:20 +0100544 u16 *variable_name, efi_guid_t *vendor)
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200545{
Heinrich Schuchardt5be59712020-03-24 19:54:53 +0000546 return efi_get_next_variable_name_int(variable_name_size, variable_name,
547 vendor);
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200548}
549
550/**
551 * efi_set_variable_runtime() - runtime implementation of SetVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +0200552 *
553 * @variable_name: name of the variable
554 * @vendor: vendor GUID
555 * @attributes: attributes of the variable
556 * @data_size: size of the buffer with the variable value
557 * @data: buffer with the variable value
558 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200559 */
560static efi_status_t __efi_runtime EFIAPI
561efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
562 u32 attributes, efi_uintn_t data_size,
563 const void *data)
564{
565 return EFI_UNSUPPORTED;
566}
567
568/**
569 * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
570 */
571void efi_variables_boot_exit_notify(void)
572{
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000573 /* Switch variable services functions to runtime version */
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200574 efi_runtime_services.get_variable = efi_get_variable_runtime;
575 efi_runtime_services.get_next_variable_name =
576 efi_get_next_variable_name_runtime;
577 efi_runtime_services.set_variable = efi_set_variable_runtime;
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200578 efi_runtime_services.query_variable_info =
579 efi_query_variable_info_runtime;
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200580 efi_update_table_header_crc32(&efi_runtime_services.hdr);
581}
582
583/**
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +0200584 * efi_init_variables() - initialize variable services
585 *
586 * Return: status code
587 */
588efi_status_t efi_init_variables(void)
589{
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900590 efi_status_t ret;
591
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200592 ret = efi_var_mem_init();
593 if (ret != EFI_SUCCESS)
594 return ret;
595
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900596 ret = efi_init_secure_state();
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000597 if (ret != EFI_SUCCESS)
598 return ret;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900599
Heinrich Schuchardt4b7d5c12020-07-14 21:25:28 +0200600 if (IS_ENABLED(CONFIG_EFI_VARIABLES_PRESEED)) {
601 ret = efi_var_restore((struct efi_var_file *)
602 __efi_var_file_begin);
603 if (ret != EFI_SUCCESS)
604 log_err("Invalid EFI variable seed\n");
605 }
606
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000607 return efi_var_from_file();
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +0200608}