blob: ecbc4f7f542decc5c680fda727ceee4a0eccd6ac [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 Takahirob0f49ee2020-04-14 11:51:41 +090022
23#ifdef CONFIG_EFI_SECURE_BOOT
24static u8 pkcs7_hdr[] = {
25 /* SEQUENCE */
26 0x30, 0x82, 0x05, 0xc7,
27 /* OID: pkcs7-signedData */
28 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02,
29 /* Context Structured? */
30 0xa0, 0x82, 0x05, 0xb8,
31};
32
33/**
34 * efi_variable_parse_signature - parse a signature in variable
35 * @buf: Pointer to variable's value
36 * @buflen: Length of @buf
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +010037 *
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090038 * Parse a signature embedded in variable's value and instantiate
39 * a pkcs7_message structure. Since pkcs7_parse_message() accepts only
40 * pkcs7's signedData, some header needed be prepended for correctly
41 * parsing authentication data, particularly for variable's.
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +010042 *
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090043 * Return: Pointer to pkcs7_message structure on success, NULL on error
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +010044 */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090045static struct pkcs7_message *efi_variable_parse_signature(const void *buf,
46 size_t buflen)
47{
48 u8 *ebuf;
49 size_t ebuflen, len;
50 struct pkcs7_message *msg;
51
52 /*
53 * This is the best assumption to check if the binary is
54 * already in a form of pkcs7's signedData.
55 */
56 if (buflen > sizeof(pkcs7_hdr) &&
57 !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) {
58 msg = pkcs7_parse_message(buf, buflen);
59 goto out;
60 }
61
62 /*
63 * Otherwise, we should add a dummy prefix sequence for pkcs7
64 * message parser to be able to process.
65 * NOTE: EDK2 also uses similar hack in WrapPkcs7Data()
66 * in CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c
67 * TODO:
68 * The header should be composed in a more refined manner.
69 */
AKASHI Takahiro37123732020-06-09 14:09:34 +090070 EFI_PRINT("Makeshift prefix added to authentication data\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090071 ebuflen = sizeof(pkcs7_hdr) + buflen;
72 if (ebuflen <= 0x7f) {
AKASHI Takahiro37123732020-06-09 14:09:34 +090073 EFI_PRINT("Data is too short\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090074 return NULL;
75 }
76
77 ebuf = malloc(ebuflen);
78 if (!ebuf) {
AKASHI Takahiro37123732020-06-09 14:09:34 +090079 EFI_PRINT("Out of memory\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +090080 return NULL;
81 }
82
83 memcpy(ebuf, pkcs7_hdr, sizeof(pkcs7_hdr));
84 memcpy(ebuf + sizeof(pkcs7_hdr), buf, buflen);
85 len = ebuflen - 4;
86 ebuf[2] = (len >> 8) & 0xff;
87 ebuf[3] = len & 0xff;
88 len = ebuflen - 0x13;
89 ebuf[0x11] = (len >> 8) & 0xff;
90 ebuf[0x12] = len & 0xff;
91
92 msg = pkcs7_parse_message(ebuf, ebuflen);
93
94 free(ebuf);
95
96out:
97 if (IS_ERR(msg))
98 return NULL;
99
100 return msg;
101}
102
103/**
104 * efi_variable_authenticate - authenticate a variable
105 * @variable: Variable name in u16
106 * @vendor: Guid of variable
107 * @data_size: Size of @data
108 * @data: Pointer to variable's value
109 * @given_attr: Attributes to be given at SetVariable()
110 * @env_attr: Attributes that an existing variable holds
111 * @time: signed time that an existing variable holds
112 *
113 * Called by efi_set_variable() to verify that the input is correct.
114 * Will replace the given data pointer with another that points to
115 * the actual data to store in the internal memory.
116 * On success, @data and @data_size will be replaced with variable's
117 * actual data, excluding authentication data, and its size, and variable's
118 * attributes and signed time will also be returned in @env_attr and @time,
119 * respectively.
120 *
Heinrich Schuchardte2c43da2020-05-03 16:29:00 +0200121 * Return: status code
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900122 */
123static efi_status_t efi_variable_authenticate(u16 *variable,
124 const efi_guid_t *vendor,
125 efi_uintn_t *data_size,
126 const void **data, u32 given_attr,
127 u32 *env_attr, u64 *time)
128{
129 const struct efi_variable_authentication_2 *auth;
130 struct efi_signature_store *truststore, *truststore2;
131 struct pkcs7_message *var_sig;
132 struct efi_image_regions *regs;
133 struct efi_time timestamp;
134 struct rtc_time tm;
135 u64 new_time;
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200136 enum efi_auth_var_type var_type;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900137 efi_status_t ret;
138
139 var_sig = NULL;
140 truststore = NULL;
141 truststore2 = NULL;
142 regs = NULL;
143 ret = EFI_SECURITY_VIOLATION;
144
145 if (*data_size < sizeof(struct efi_variable_authentication_2))
146 goto err;
147
148 /* authentication data */
149 auth = *data;
150 if (*data_size < (sizeof(auth->time_stamp)
151 + auth->auth_info.hdr.dwLength))
152 goto err;
153
154 if (guidcmp(&auth->auth_info.cert_type, &efi_guid_cert_type_pkcs7))
155 goto err;
156
Heinrich Schuchardt7a76a3f2020-07-01 12:44:00 +0200157 memcpy(&timestamp, &auth->time_stamp, sizeof(timestamp));
158 if (timestamp.pad1 || timestamp.nanosecond || timestamp.timezone ||
159 timestamp.daylight || timestamp.pad2)
160 goto err;
161
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900162 *data += sizeof(auth->time_stamp) + auth->auth_info.hdr.dwLength;
163 *data_size -= (sizeof(auth->time_stamp)
164 + auth->auth_info.hdr.dwLength);
165
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900166 memset(&tm, 0, sizeof(tm));
167 tm.tm_year = timestamp.year;
168 tm.tm_mon = timestamp.month;
169 tm.tm_mday = timestamp.day;
170 tm.tm_hour = timestamp.hour;
171 tm.tm_min = timestamp.minute;
172 tm.tm_sec = timestamp.second;
173 new_time = rtc_mktime(&tm);
174
175 if (!efi_secure_boot_enabled()) {
176 /* finished checking */
177 *time = new_time;
178 return EFI_SUCCESS;
179 }
180
181 if (new_time <= *time)
182 goto err;
183
184 /* data to be digested */
185 regs = calloc(sizeof(*regs) + sizeof(struct image_region) * 5, 1);
186 if (!regs)
187 goto err;
188 regs->max = 5;
189 efi_image_region_add(regs, (uint8_t *)variable,
190 (uint8_t *)variable
191 + u16_strlen(variable) * sizeof(u16), 1);
192 efi_image_region_add(regs, (uint8_t *)vendor,
193 (uint8_t *)vendor + sizeof(*vendor), 1);
194 efi_image_region_add(regs, (uint8_t *)&given_attr,
195 (uint8_t *)&given_attr + sizeof(given_attr), 1);
196 efi_image_region_add(regs, (uint8_t *)&timestamp,
197 (uint8_t *)&timestamp + sizeof(timestamp), 1);
198 efi_image_region_add(regs, (uint8_t *)*data,
199 (uint8_t *)*data + *data_size, 1);
200
201 /* variable's signature list */
202 if (auth->auth_info.hdr.dwLength < sizeof(auth->auth_info))
203 goto err;
204 var_sig = efi_variable_parse_signature(auth->auth_info.cert_data,
205 auth->auth_info.hdr.dwLength
206 - sizeof(auth->auth_info));
Patrick Wildtcd8a55b2020-05-07 02:13:18 +0200207 if (!var_sig) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900208 EFI_PRINT("Parsing variable's signature failed\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900209 goto err;
210 }
211
212 /* signature database used for authentication */
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200213 var_type = efi_auth_var_get_type(variable, vendor);
214 switch (var_type) {
215 case EFI_AUTH_VAR_PK:
216 case EFI_AUTH_VAR_KEK:
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900217 /* with PK */
218 truststore = efi_sigstore_parse_sigdb(L"PK");
219 if (!truststore)
220 goto err;
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200221 break;
222 case EFI_AUTH_VAR_DB:
223 case EFI_AUTH_VAR_DBX:
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900224 /* with PK and KEK */
225 truststore = efi_sigstore_parse_sigdb(L"KEK");
226 truststore2 = efi_sigstore_parse_sigdb(L"PK");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900227 if (!truststore) {
228 if (!truststore2)
229 goto err;
230
231 truststore = truststore2;
232 truststore2 = NULL;
233 }
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200234 break;
235 default:
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900236 /* TODO: support private authenticated variables */
237 goto err;
238 }
239
240 /* verify signature */
241 if (efi_signature_verify_with_sigdb(regs, var_sig, truststore, NULL)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900242 EFI_PRINT("Verified\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900243 } else {
244 if (truststore2 &&
245 efi_signature_verify_with_sigdb(regs, var_sig,
246 truststore2, NULL)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900247 EFI_PRINT("Verified\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900248 } else {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900249 EFI_PRINT("Verifying variable's signature failed\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900250 goto err;
251 }
252 }
253
254 /* finished checking */
Heinrich Schuchardt5106dc72020-06-30 12:02:14 +0200255 *time = new_time;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900256 ret = EFI_SUCCESS;
257
258err:
259 efi_sigstore_free(truststore);
260 efi_sigstore_free(truststore2);
261 pkcs7_free_message(var_sig);
262 free(regs);
263
264 return ret;
265}
266#else
267static efi_status_t efi_variable_authenticate(u16 *variable,
268 const efi_guid_t *vendor,
269 efi_uintn_t *data_size,
270 const void **data, u32 given_attr,
271 u32 *env_attr, u64 *time)
272{
273 return EFI_SUCCESS;
274}
275#endif /* CONFIG_EFI_SECURE_BOOT */
276
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200277efi_status_t __efi_runtime
278efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
279 u32 *attributes, efi_uintn_t *data_size, void *data,
280 u64 *timep)
Rob Clark15f3d742017-09-13 18:05:37 -0400281{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200282 efi_uintn_t old_size;
283 struct efi_var_entry *var;
284 u16 *pdata;
Rob Clark15f3d742017-09-13 18:05:37 -0400285
Rob Clark15f3d742017-09-13 18:05:37 -0400286 if (!variable_name || !vendor || !data_size)
Heinrich Schuchardt563e5522020-06-29 11:49:58 +0200287 return EFI_INVALID_PARAMETER;
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200288 var = efi_var_mem_find(vendor, variable_name, NULL);
289 if (!var)
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900290 return EFI_NOT_FOUND;
Rob Clark15f3d742017-09-13 18:05:37 -0400291
Rob Clark15f3d742017-09-13 18:05:37 -0400292 if (attributes)
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200293 *attributes = var->attr;
294 if (timep)
295 *timep = var->time;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100296
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200297 old_size = *data_size;
298 *data_size = var->length;
299 if (old_size < var->length)
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100300 return EFI_BUFFER_TOO_SMALL;
Heinrich Schuchardt31d9b3a2020-03-20 19:04:34 +0100301
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200302 if (!data)
AKASHI Takahiro4854f782020-05-08 14:51:21 +0900303 return EFI_INVALID_PARAMETER;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100304
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200305 for (pdata = var->name; *pdata; ++pdata)
306 ;
307 ++pdata;
308
309 efi_memcpy_runtime(data, pdata, var->length);
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100310
311 return EFI_SUCCESS;
312}
313
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200314efi_status_t __efi_runtime
315efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
316 u16 *variable_name, efi_guid_t *vendor)
Rob Clark15f3d742017-09-13 18:05:37 -0400317{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200318 struct efi_var_entry *var;
319 efi_uintn_t old_size;
320 u16 *pdata;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100321
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100322 if (!variable_name_size || !variable_name || !vendor)
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200323 return EFI_INVALID_PARAMETER;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100324
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200325 efi_var_mem_find(vendor, variable_name, &var);
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100326
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200327 if (!var)
328 return EFI_NOT_FOUND;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100329
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200330 for (pdata = var->name; *pdata; ++pdata)
331 ;
332 ++pdata;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900333
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200334 old_size = *variable_name_size;
335 *variable_name_size = (uintptr_t)pdata - (uintptr_t)var->name;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100336
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200337 if (old_size < *variable_name_size)
338 return EFI_BUFFER_TOO_SMALL;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100339
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200340 efi_memcpy_runtime(variable_name, var->name, *variable_name_size);
341 efi_memcpy_runtime(vendor, &var->guid, sizeof(efi_guid_t));
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100342
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200343 return EFI_SUCCESS;
Rob Clark15f3d742017-09-13 18:05:37 -0400344}
345
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200346efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor,
347 u32 attributes, efi_uintn_t data_size,
348 const void *data, bool ro_check)
Rob Clark15f3d742017-09-13 18:05:37 -0400349{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200350 struct efi_var_entry *var;
351 efi_uintn_t ret;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900352 bool append, delete;
353 u64 time = 0;
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200354 enum efi_auth_var_type var_type;
Rob Clark15f3d742017-09-13 18:05:37 -0400355
Heinrich Schuchardtadba3962019-06-12 23:28:42 +0200356 if (!variable_name || !*variable_name || !vendor ||
357 ((attributes & EFI_VARIABLE_RUNTIME_ACCESS) &&
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200358 !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)))
359 return EFI_INVALID_PARAMETER;
Rob Clark15f3d742017-09-13 18:05:37 -0400360
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900361 /* check if a variable exists */
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200362 var = efi_var_mem_find(vendor, variable_name, NULL);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900363 append = !!(attributes & EFI_VARIABLE_APPEND_WRITE);
364 attributes &= ~(u32)EFI_VARIABLE_APPEND_WRITE;
365 delete = !append && (!data_size || !attributes);
366
367 /* check attributes */
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200368 if (var) {
369 if (ro_check && (var->attr & EFI_VARIABLE_READ_ONLY))
370 return EFI_WRITE_PROTECTED;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900371
372 /* attributes won't be changed */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900373 if (!delete &&
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200374 ((ro_check && var->attr != attributes) ||
375 (!ro_check && ((var->attr & ~(u32)EFI_VARIABLE_READ_ONLY)
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200376 != (attributes & ~(u32)EFI_VARIABLE_READ_ONLY))))) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200377 return EFI_INVALID_PARAMETER;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900378 }
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200379 time = var->time;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900380 } else {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200381 if (delete || append)
Heinrich Schuchardt8021bbe2019-09-26 21:40:18 +0200382 /*
383 * Trying to delete or to update a non-existent
384 * variable.
385 */
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200386 return EFI_NOT_FOUND;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900387 }
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900388
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200389 var_type = efi_auth_var_get_type(variable_name, vendor);
390 if (var_type != EFI_AUTH_VAR_NONE) {
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900391 /* authentication is mandatory */
392 if (!(attributes &
393 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200394 EFI_PRINT("%ls: TIME_BASED_AUTHENTICATED_WRITE_ACCESS required\n",
AKASHI Takahiro37123732020-06-09 14:09:34 +0900395 variable_name);
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200396 return EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900397 }
398 }
399
400 /* authenticate a variable */
401 if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200402 if (attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
403 return EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900404 if (attributes &
405 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200406 u32 env_attr;
407
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900408 ret = efi_variable_authenticate(variable_name, vendor,
409 &data_size, &data,
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200410 attributes, &env_attr,
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900411 &time);
412 if (ret != EFI_SUCCESS)
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200413 return ret;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900414
415 /* last chance to check for delete */
416 if (!data_size)
417 delete = true;
418 }
419 } else {
420 if (attributes &
421 (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS |
422 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900423 EFI_PRINT("Secure boot is not configured\n");
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200424 return EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900425 }
426 }
427
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900428 if (delete) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200429 /* EFI_NOT_FOUND has been handled before */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900430 ret = EFI_SUCCESS;
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200431 } else if (append) {
432 u16 *old_data = var->name;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900433
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200434 for (; *old_data; ++old_data)
435 ;
436 ++old_data;
437 ret = efi_var_mem_ins(variable_name, vendor, attributes,
438 var->length, old_data, data_size, data,
439 time);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900440 } else {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200441 ret = efi_var_mem_ins(variable_name, vendor, attributes,
442 data_size, data, 0, NULL, time);
Rob Clark15f3d742017-09-13 18:05:37 -0400443 }
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200444 efi_var_mem_del(var);
Rob Clark15f3d742017-09-13 18:05:37 -0400445
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200446 if (ret != EFI_SUCCESS)
447 return ret;
Rob Clark15f3d742017-09-13 18:05:37 -0400448
Heinrich Schuchardt3a280332020-07-15 12:40:35 +0200449 if (var_type == EFI_AUTH_VAR_PK)
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200450 ret = efi_init_secure_state();
451 else
452 ret = EFI_SUCCESS;
Rob Clark15f3d742017-09-13 18:05:37 -0400453
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000454 /* Write non-volatile EFI variables to file */
455 if (attributes & EFI_VARIABLE_NON_VOLATILE &&
456 ret == EFI_SUCCESS && efi_obj_list_initialized == EFI_SUCCESS)
457 efi_var_to_file();
458
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200459 return EFI_SUCCESS;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900460}
461
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200462efi_status_t efi_query_variable_info_int(u32 attributes,
463 u64 *maximum_variable_storage_size,
464 u64 *remaining_variable_storage_size,
465 u64 *maximum_variable_size)
466{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200467 *maximum_variable_storage_size = EFI_VAR_BUF_SIZE -
468 sizeof(struct efi_var_file);
469 *remaining_variable_storage_size = efi_var_mem_free();
470 *maximum_variable_size = EFI_VAR_BUF_SIZE -
471 sizeof(struct efi_var_file) -
472 sizeof(struct efi_var_entry);
473 return EFI_SUCCESS;
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200474}
475
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900476/**
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200477 * efi_query_variable_info_runtime() - runtime implementation of
478 * QueryVariableInfo()
Heinrich Schuchardt9b19dae2019-06-20 12:13:05 +0200479 *
480 * @attributes: bitmask to select variables to be
481 * queried
482 * @maximum_variable_storage_size: maximum size of storage area for the
483 * selected variable types
484 * @remaining_variable_storage_size: remaining size of storage are for the
485 * selected variable types
486 * @maximum_variable_size: maximum size of a variable of the
487 * selected type
488 * Returns: status code
489 */
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200490efi_status_t __efi_runtime EFIAPI efi_query_variable_info_runtime(
Heinrich Schuchardt9b19dae2019-06-20 12:13:05 +0200491 u32 attributes,
492 u64 *maximum_variable_storage_size,
493 u64 *remaining_variable_storage_size,
494 u64 *maximum_variable_size)
495{
496 return EFI_UNSUPPORTED;
497}
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +0200498
499/**
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200500 * efi_get_variable_runtime() - runtime implementation of GetVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +0200501 *
502 * @variable_name: name of the variable
503 * @vendor: vendor GUID
504 * @attributes: attributes of the variable
505 * @data_size: size of the buffer to which the variable value is copied
506 * @data: buffer to which the variable value is copied
507 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200508 */
509static efi_status_t __efi_runtime EFIAPI
510efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
511 u32 *attributes, efi_uintn_t *data_size, void *data)
512{
Heinrich Schuchardt5be59712020-03-24 19:54:53 +0000513 efi_status_t ret;
514
515 ret = efi_get_variable_int(variable_name, vendor, attributes,
516 data_size, data, NULL);
517
518 /* Remove EFI_VARIABLE_READ_ONLY flag */
519 if (attributes)
520 *attributes &= EFI_VARIABLE_MASK;
521
522 return ret;
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200523}
524
525/**
526 * efi_get_next_variable_name_runtime() - runtime implementation of
527 * GetNextVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +0200528 *
529 * @variable_name_size: size of variable_name buffer in byte
530 * @variable_name: name of uefi variable's name in u16
531 * @vendor: vendor's guid
532 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200533 */
534static efi_status_t __efi_runtime EFIAPI
535efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
Heinrich Schuchardt82cd6c42020-03-22 18:28:20 +0100536 u16 *variable_name, efi_guid_t *vendor)
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200537{
Heinrich Schuchardt5be59712020-03-24 19:54:53 +0000538 return efi_get_next_variable_name_int(variable_name_size, variable_name,
539 vendor);
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200540}
541
542/**
543 * efi_set_variable_runtime() - runtime implementation of SetVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +0200544 *
545 * @variable_name: name of the variable
546 * @vendor: vendor GUID
547 * @attributes: attributes of the variable
548 * @data_size: size of the buffer with the variable value
549 * @data: buffer with the variable value
550 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200551 */
552static efi_status_t __efi_runtime EFIAPI
553efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
554 u32 attributes, efi_uintn_t data_size,
555 const void *data)
556{
557 return EFI_UNSUPPORTED;
558}
559
560/**
561 * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
562 */
563void efi_variables_boot_exit_notify(void)
564{
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000565 /* Switch variable services functions to runtime version */
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200566 efi_runtime_services.get_variable = efi_get_variable_runtime;
567 efi_runtime_services.get_next_variable_name =
568 efi_get_next_variable_name_runtime;
569 efi_runtime_services.set_variable = efi_set_variable_runtime;
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200570 efi_runtime_services.query_variable_info =
571 efi_query_variable_info_runtime;
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200572 efi_update_table_header_crc32(&efi_runtime_services.hdr);
573}
574
575/**
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +0200576 * efi_init_variables() - initialize variable services
577 *
578 * Return: status code
579 */
580efi_status_t efi_init_variables(void)
581{
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900582 efi_status_t ret;
583
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200584 ret = efi_var_mem_init();
585 if (ret != EFI_SUCCESS)
586 return ret;
587
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900588 ret = efi_init_secure_state();
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000589 if (ret != EFI_SUCCESS)
590 return ret;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900591
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000592 return efi_var_from_file();
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +0200593}