blob: 64dc3d6df95b215b59cd72a0f440fcebfa98f0a2 [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;
136 efi_status_t ret;
137
138 var_sig = NULL;
139 truststore = NULL;
140 truststore2 = NULL;
141 regs = NULL;
142 ret = EFI_SECURITY_VIOLATION;
143
144 if (*data_size < sizeof(struct efi_variable_authentication_2))
145 goto err;
146
147 /* authentication data */
148 auth = *data;
149 if (*data_size < (sizeof(auth->time_stamp)
150 + auth->auth_info.hdr.dwLength))
151 goto err;
152
153 if (guidcmp(&auth->auth_info.cert_type, &efi_guid_cert_type_pkcs7))
154 goto err;
155
Heinrich Schuchardt7a76a3f2020-07-01 12:44:00 +0200156 memcpy(&timestamp, &auth->time_stamp, sizeof(timestamp));
157 if (timestamp.pad1 || timestamp.nanosecond || timestamp.timezone ||
158 timestamp.daylight || timestamp.pad2)
159 goto err;
160
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900161 *data += sizeof(auth->time_stamp) + auth->auth_info.hdr.dwLength;
162 *data_size -= (sizeof(auth->time_stamp)
163 + auth->auth_info.hdr.dwLength);
164
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900165 memset(&tm, 0, sizeof(tm));
166 tm.tm_year = timestamp.year;
167 tm.tm_mon = timestamp.month;
168 tm.tm_mday = timestamp.day;
169 tm.tm_hour = timestamp.hour;
170 tm.tm_min = timestamp.minute;
171 tm.tm_sec = timestamp.second;
172 new_time = rtc_mktime(&tm);
173
174 if (!efi_secure_boot_enabled()) {
175 /* finished checking */
176 *time = new_time;
177 return EFI_SUCCESS;
178 }
179
180 if (new_time <= *time)
181 goto err;
182
183 /* data to be digested */
184 regs = calloc(sizeof(*regs) + sizeof(struct image_region) * 5, 1);
185 if (!regs)
186 goto err;
187 regs->max = 5;
188 efi_image_region_add(regs, (uint8_t *)variable,
189 (uint8_t *)variable
190 + u16_strlen(variable) * sizeof(u16), 1);
191 efi_image_region_add(regs, (uint8_t *)vendor,
192 (uint8_t *)vendor + sizeof(*vendor), 1);
193 efi_image_region_add(regs, (uint8_t *)&given_attr,
194 (uint8_t *)&given_attr + sizeof(given_attr), 1);
195 efi_image_region_add(regs, (uint8_t *)&timestamp,
196 (uint8_t *)&timestamp + sizeof(timestamp), 1);
197 efi_image_region_add(regs, (uint8_t *)*data,
198 (uint8_t *)*data + *data_size, 1);
199
200 /* variable's signature list */
201 if (auth->auth_info.hdr.dwLength < sizeof(auth->auth_info))
202 goto err;
203 var_sig = efi_variable_parse_signature(auth->auth_info.cert_data,
204 auth->auth_info.hdr.dwLength
205 - sizeof(auth->auth_info));
Patrick Wildtcd8a55b2020-05-07 02:13:18 +0200206 if (!var_sig) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900207 EFI_PRINT("Parsing variable's signature failed\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900208 goto err;
209 }
210
211 /* signature database used for authentication */
212 if (u16_strcmp(variable, L"PK") == 0 ||
213 u16_strcmp(variable, L"KEK") == 0) {
214 /* with PK */
215 truststore = efi_sigstore_parse_sigdb(L"PK");
216 if (!truststore)
217 goto err;
218 } else if (u16_strcmp(variable, L"db") == 0 ||
219 u16_strcmp(variable, L"dbx") == 0) {
220 /* with PK and KEK */
221 truststore = efi_sigstore_parse_sigdb(L"KEK");
222 truststore2 = efi_sigstore_parse_sigdb(L"PK");
223
224 if (!truststore) {
225 if (!truststore2)
226 goto err;
227
228 truststore = truststore2;
229 truststore2 = NULL;
230 }
231 } else {
232 /* TODO: support private authenticated variables */
233 goto err;
234 }
235
236 /* verify signature */
237 if (efi_signature_verify_with_sigdb(regs, var_sig, truststore, NULL)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900238 EFI_PRINT("Verified\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900239 } else {
240 if (truststore2 &&
241 efi_signature_verify_with_sigdb(regs, var_sig,
242 truststore2, NULL)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900243 EFI_PRINT("Verified\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900244 } else {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900245 EFI_PRINT("Verifying variable's signature failed\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900246 goto err;
247 }
248 }
249
250 /* finished checking */
Heinrich Schuchardt5106dc72020-06-30 12:02:14 +0200251 *time = new_time;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900252 ret = EFI_SUCCESS;
253
254err:
255 efi_sigstore_free(truststore);
256 efi_sigstore_free(truststore2);
257 pkcs7_free_message(var_sig);
258 free(regs);
259
260 return ret;
261}
262#else
263static efi_status_t efi_variable_authenticate(u16 *variable,
264 const efi_guid_t *vendor,
265 efi_uintn_t *data_size,
266 const void **data, u32 given_attr,
267 u32 *env_attr, u64 *time)
268{
269 return EFI_SUCCESS;
270}
271#endif /* CONFIG_EFI_SECURE_BOOT */
272
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200273efi_status_t __efi_runtime
274efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
275 u32 *attributes, efi_uintn_t *data_size, void *data,
276 u64 *timep)
Rob Clark15f3d742017-09-13 18:05:37 -0400277{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200278 efi_uintn_t old_size;
279 struct efi_var_entry *var;
280 u16 *pdata;
Rob Clark15f3d742017-09-13 18:05:37 -0400281
Rob Clark15f3d742017-09-13 18:05:37 -0400282 if (!variable_name || !vendor || !data_size)
Heinrich Schuchardt563e5522020-06-29 11:49:58 +0200283 return EFI_INVALID_PARAMETER;
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200284 var = efi_var_mem_find(vendor, variable_name, NULL);
285 if (!var)
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900286 return EFI_NOT_FOUND;
Rob Clark15f3d742017-09-13 18:05:37 -0400287
Rob Clark15f3d742017-09-13 18:05:37 -0400288 if (attributes)
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200289 *attributes = var->attr;
290 if (timep)
291 *timep = var->time;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100292
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200293 old_size = *data_size;
294 *data_size = var->length;
295 if (old_size < var->length)
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100296 return EFI_BUFFER_TOO_SMALL;
Heinrich Schuchardt31d9b3a2020-03-20 19:04:34 +0100297
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200298 if (!data)
AKASHI Takahiro4854f782020-05-08 14:51:21 +0900299 return EFI_INVALID_PARAMETER;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100300
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200301 for (pdata = var->name; *pdata; ++pdata)
302 ;
303 ++pdata;
304
305 efi_memcpy_runtime(data, pdata, var->length);
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100306
307 return EFI_SUCCESS;
308}
309
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200310efi_status_t __efi_runtime
311efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
312 u16 *variable_name, efi_guid_t *vendor)
Rob Clark15f3d742017-09-13 18:05:37 -0400313{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200314 struct efi_var_entry *var;
315 efi_uintn_t old_size;
316 u16 *pdata;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100317
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100318 if (!variable_name_size || !variable_name || !vendor)
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200319 return EFI_INVALID_PARAMETER;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100320
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200321 efi_var_mem_find(vendor, variable_name, &var);
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100322
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200323 if (!var)
324 return EFI_NOT_FOUND;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100325
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200326 for (pdata = var->name; *pdata; ++pdata)
327 ;
328 ++pdata;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900329
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200330 old_size = *variable_name_size;
331 *variable_name_size = (uintptr_t)pdata - (uintptr_t)var->name;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100332
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200333 if (old_size < *variable_name_size)
334 return EFI_BUFFER_TOO_SMALL;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100335
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200336 efi_memcpy_runtime(variable_name, var->name, *variable_name_size);
337 efi_memcpy_runtime(vendor, &var->guid, sizeof(efi_guid_t));
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100338
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200339 return EFI_SUCCESS;
Rob Clark15f3d742017-09-13 18:05:37 -0400340}
341
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200342efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor,
343 u32 attributes, efi_uintn_t data_size,
344 const void *data, bool ro_check)
Rob Clark15f3d742017-09-13 18:05:37 -0400345{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200346 struct efi_var_entry *var;
347 efi_uintn_t ret;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900348 bool append, delete;
349 u64 time = 0;
Rob Clark15f3d742017-09-13 18:05:37 -0400350
Heinrich Schuchardtadba3962019-06-12 23:28:42 +0200351 if (!variable_name || !*variable_name || !vendor ||
352 ((attributes & EFI_VARIABLE_RUNTIME_ACCESS) &&
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200353 !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)))
354 return EFI_INVALID_PARAMETER;
Rob Clark15f3d742017-09-13 18:05:37 -0400355
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900356 /* check if a variable exists */
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200357 var = efi_var_mem_find(vendor, variable_name, NULL);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900358 append = !!(attributes & EFI_VARIABLE_APPEND_WRITE);
359 attributes &= ~(u32)EFI_VARIABLE_APPEND_WRITE;
360 delete = !append && (!data_size || !attributes);
361
362 /* check attributes */
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200363 if (var) {
364 if (ro_check && (var->attr & EFI_VARIABLE_READ_ONLY))
365 return EFI_WRITE_PROTECTED;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900366
367 /* attributes won't be changed */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900368 if (!delete &&
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200369 ((ro_check && var->attr != attributes) ||
370 (!ro_check && ((var->attr & ~(u32)EFI_VARIABLE_READ_ONLY)
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200371 != (attributes & ~(u32)EFI_VARIABLE_READ_ONLY))))) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200372 return EFI_INVALID_PARAMETER;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900373 }
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200374 time = var->time;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900375 } else {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200376 if (delete || append)
Heinrich Schuchardt8021bbe2019-09-26 21:40:18 +0200377 /*
378 * Trying to delete or to update a non-existent
379 * variable.
380 */
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200381 return EFI_NOT_FOUND;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900382 }
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900383
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900384 if (((!u16_strcmp(variable_name, L"PK") ||
385 !u16_strcmp(variable_name, L"KEK")) &&
386 !guidcmp(vendor, &efi_global_variable_guid)) ||
387 ((!u16_strcmp(variable_name, L"db") ||
388 !u16_strcmp(variable_name, L"dbx")) &&
389 !guidcmp(vendor, &efi_guid_image_security_database))) {
390 /* authentication is mandatory */
391 if (!(attributes &
392 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200393 EFI_PRINT("%ls: TIME_BASED_AUTHENTICATED_WRITE_ACCESS required\n",
AKASHI Takahiro37123732020-06-09 14:09:34 +0900394 variable_name);
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200395 return EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900396 }
397 }
398
399 /* authenticate a variable */
400 if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200401 if (attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
402 return EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900403 if (attributes &
404 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200405 u32 env_attr;
406
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900407 ret = efi_variable_authenticate(variable_name, vendor,
408 &data_size, &data,
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200409 attributes, &env_attr,
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900410 &time);
411 if (ret != EFI_SUCCESS)
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200412 return ret;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900413
414 /* last chance to check for delete */
415 if (!data_size)
416 delete = true;
417 }
418 } else {
419 if (attributes &
420 (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS |
421 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900422 EFI_PRINT("Secure boot is not configured\n");
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200423 return EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900424 }
425 }
426
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900427 if (delete) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200428 /* EFI_NOT_FOUND has been handled before */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900429 ret = EFI_SUCCESS;
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200430 } else if (append) {
431 u16 *old_data = var->name;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900432
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200433 for (; *old_data; ++old_data)
434 ;
435 ++old_data;
436 ret = efi_var_mem_ins(variable_name, vendor, attributes,
437 var->length, old_data, data_size, data,
438 time);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900439 } else {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200440 ret = efi_var_mem_ins(variable_name, vendor, attributes,
441 data_size, data, 0, NULL, time);
Rob Clark15f3d742017-09-13 18:05:37 -0400442 }
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200443 efi_var_mem_del(var);
Rob Clark15f3d742017-09-13 18:05:37 -0400444
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200445 if (ret != EFI_SUCCESS)
446 return ret;
Rob Clark15f3d742017-09-13 18:05:37 -0400447
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200448 if (!u16_strcmp(variable_name, L"PK"))
449 ret = efi_init_secure_state();
450 else
451 ret = EFI_SUCCESS;
Rob Clark15f3d742017-09-13 18:05:37 -0400452
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000453 /* Write non-volatile EFI variables to file */
454 if (attributes & EFI_VARIABLE_NON_VOLATILE &&
455 ret == EFI_SUCCESS && efi_obj_list_initialized == EFI_SUCCESS)
456 efi_var_to_file();
457
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200458 return EFI_SUCCESS;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900459}
460
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200461efi_status_t efi_query_variable_info_int(u32 attributes,
462 u64 *maximum_variable_storage_size,
463 u64 *remaining_variable_storage_size,
464 u64 *maximum_variable_size)
465{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200466 *maximum_variable_storage_size = EFI_VAR_BUF_SIZE -
467 sizeof(struct efi_var_file);
468 *remaining_variable_storage_size = efi_var_mem_free();
469 *maximum_variable_size = EFI_VAR_BUF_SIZE -
470 sizeof(struct efi_var_file) -
471 sizeof(struct efi_var_entry);
472 return EFI_SUCCESS;
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200473}
474
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900475/**
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200476 * efi_query_variable_info_runtime() - runtime implementation of
477 * QueryVariableInfo()
Heinrich Schuchardt9b19dae2019-06-20 12:13:05 +0200478 *
479 * @attributes: bitmask to select variables to be
480 * queried
481 * @maximum_variable_storage_size: maximum size of storage area for the
482 * selected variable types
483 * @remaining_variable_storage_size: remaining size of storage are for the
484 * selected variable types
485 * @maximum_variable_size: maximum size of a variable of the
486 * selected type
487 * Returns: status code
488 */
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200489efi_status_t __efi_runtime EFIAPI efi_query_variable_info_runtime(
Heinrich Schuchardt9b19dae2019-06-20 12:13:05 +0200490 u32 attributes,
491 u64 *maximum_variable_storage_size,
492 u64 *remaining_variable_storage_size,
493 u64 *maximum_variable_size)
494{
495 return EFI_UNSUPPORTED;
496}
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +0200497
498/**
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200499 * efi_get_variable_runtime() - runtime implementation of GetVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +0200500 *
501 * @variable_name: name of the variable
502 * @vendor: vendor GUID
503 * @attributes: attributes of the variable
504 * @data_size: size of the buffer to which the variable value is copied
505 * @data: buffer to which the variable value is copied
506 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200507 */
508static efi_status_t __efi_runtime EFIAPI
509efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
510 u32 *attributes, efi_uintn_t *data_size, void *data)
511{
Heinrich Schuchardt5be59712020-03-24 19:54:53 +0000512 efi_status_t ret;
513
514 ret = efi_get_variable_int(variable_name, vendor, attributes,
515 data_size, data, NULL);
516
517 /* Remove EFI_VARIABLE_READ_ONLY flag */
518 if (attributes)
519 *attributes &= EFI_VARIABLE_MASK;
520
521 return ret;
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200522}
523
524/**
525 * efi_get_next_variable_name_runtime() - runtime implementation of
526 * GetNextVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +0200527 *
528 * @variable_name_size: size of variable_name buffer in byte
529 * @variable_name: name of uefi variable's name in u16
530 * @vendor: vendor's guid
531 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200532 */
533static efi_status_t __efi_runtime EFIAPI
534efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
Heinrich Schuchardt82cd6c42020-03-22 18:28:20 +0100535 u16 *variable_name, efi_guid_t *vendor)
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200536{
Heinrich Schuchardt5be59712020-03-24 19:54:53 +0000537 return efi_get_next_variable_name_int(variable_name_size, variable_name,
538 vendor);
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200539}
540
541/**
542 * efi_set_variable_runtime() - runtime implementation of SetVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +0200543 *
544 * @variable_name: name of the variable
545 * @vendor: vendor GUID
546 * @attributes: attributes of the variable
547 * @data_size: size of the buffer with the variable value
548 * @data: buffer with the variable value
549 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200550 */
551static efi_status_t __efi_runtime EFIAPI
552efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
553 u32 attributes, efi_uintn_t data_size,
554 const void *data)
555{
556 return EFI_UNSUPPORTED;
557}
558
559/**
560 * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
561 */
562void efi_variables_boot_exit_notify(void)
563{
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000564 /* Switch variable services functions to runtime version */
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200565 efi_runtime_services.get_variable = efi_get_variable_runtime;
566 efi_runtime_services.get_next_variable_name =
567 efi_get_next_variable_name_runtime;
568 efi_runtime_services.set_variable = efi_set_variable_runtime;
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200569 efi_runtime_services.query_variable_info =
570 efi_query_variable_info_runtime;
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200571 efi_update_table_header_crc32(&efi_runtime_services.hdr);
572}
573
574/**
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +0200575 * efi_init_variables() - initialize variable services
576 *
577 * Return: status code
578 */
579efi_status_t efi_init_variables(void)
580{
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900581 efi_status_t ret;
582
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200583 ret = efi_var_mem_init();
584 if (ret != EFI_SUCCESS)
585 return ret;
586
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900587 ret = efi_init_secure_state();
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000588 if (ret != EFI_SUCCESS)
589 return ret;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900590
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000591 return efi_var_from_file();
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +0200592}