blob: bbdc071126b2d1d62f965d20a4417a1104ca5629 [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
AKASHI Takahiroc78dc192020-04-14 11:51:42 +090033/**
AKASHI Takahirodae117a2020-04-21 09:39:20 +090034 * efi_set_secure_state - modify secure boot state variables
Heinrich Schuchardtbae548c2020-06-24 12:38:00 +020035 * @secure_boot: value of SecureBoot
AKASHI Takahirodae117a2020-04-21 09:39:20 +090036 * @setup_mode: value of SetupMode
37 * @audit_mode: value of AuditMode
38 * @deployed_mode: value of DeployedMode
39 *
Heinrich Schuchardtbae548c2020-06-24 12:38:00 +020040 * Modify secure boot status related variables as indicated.
AKASHI Takahirodae117a2020-04-21 09:39:20 +090041 *
42 * Return: status code
43 */
Heinrich Schuchardtbae548c2020-06-24 12:38:00 +020044static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode,
45 u8 audit_mode, u8 deployed_mode)
AKASHI Takahirodae117a2020-04-21 09:39:20 +090046{
AKASHI Takahirodae117a2020-04-21 09:39:20 +090047 efi_status_t ret;
Heinrich Schuchardt93f96252020-07-04 18:34:15 +020048 const u32 attributes_ro = EFI_VARIABLE_BOOTSERVICE_ACCESS |
49 EFI_VARIABLE_RUNTIME_ACCESS |
50 EFI_VARIABLE_READ_ONLY;
51 const u32 attributes_rw = EFI_VARIABLE_BOOTSERVICE_ACCESS |
52 EFI_VARIABLE_RUNTIME_ACCESS;
AKASHI Takahirodae117a2020-04-21 09:39:20 +090053
Heinrich Schuchardt40fbdd82020-07-05 02:29:50 +020054 efi_secure_boot = secure_boot;
55
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020056 ret = efi_set_variable_int(L"SecureBoot", &efi_global_variable_guid,
Heinrich Schuchardt93f96252020-07-04 18:34:15 +020057 attributes_ro, sizeof(secure_boot),
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020058 &secure_boot, false);
AKASHI Takahirodae117a2020-04-21 09:39:20 +090059 if (ret != EFI_SUCCESS)
60 goto err;
61
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020062 ret = efi_set_variable_int(L"SetupMode", &efi_global_variable_guid,
Heinrich Schuchardt93f96252020-07-04 18:34:15 +020063 attributes_ro, sizeof(setup_mode),
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020064 &setup_mode, false);
AKASHI Takahirodae117a2020-04-21 09:39:20 +090065 if (ret != EFI_SUCCESS)
66 goto err;
67
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020068 ret = efi_set_variable_int(L"AuditMode", &efi_global_variable_guid,
Heinrich Schuchardt93f96252020-07-04 18:34:15 +020069 audit_mode || setup_mode ?
70 attributes_ro : attributes_rw,
71 sizeof(audit_mode), &audit_mode, false);
AKASHI Takahirodae117a2020-04-21 09:39:20 +090072 if (ret != EFI_SUCCESS)
73 goto err;
74
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020075 ret = efi_set_variable_int(L"DeployedMode",
Heinrich Schuchardt93f96252020-07-04 18:34:15 +020076 &efi_global_variable_guid,
77 audit_mode || deployed_mode || setup_mode ?
78 attributes_ro : attributes_rw,
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020079 sizeof(deployed_mode), &deployed_mode,
80 false);
AKASHI Takahirodae117a2020-04-21 09:39:20 +090081err:
82 return ret;
83}
84
85/**
AKASHI Takahiroc78dc192020-04-14 11:51:42 +090086 * efi_transfer_secure_state - handle a secure boot state transition
87 * @mode: new state
88 *
89 * Depending on @mode, secure boot related variables are updated.
Heinrich Schuchardt9827e842020-06-22 18:10:27 +020090 * Those variables are *read-only* for users, efi_set_variable_int()
AKASHI Takahiroc78dc192020-04-14 11:51:42 +090091 * is called here.
92 *
Heinrich Schuchardte2c43da2020-05-03 16:29:00 +020093 * Return: status code
AKASHI Takahiroc78dc192020-04-14 11:51:42 +090094 */
95static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
96{
AKASHI Takahiroc78dc192020-04-14 11:51:42 +090097 efi_status_t ret;
98
AKASHI Takahiro37123732020-06-09 14:09:34 +090099 EFI_PRINT("Switching secure state from %d to %d\n", efi_secure_mode,
100 mode);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900101
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900102 if (mode == EFI_MODE_DEPLOYED) {
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900103 ret = efi_set_secure_state(1, 0, 0, 1);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900104 if (ret != EFI_SUCCESS)
105 goto err;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900106 } else if (mode == EFI_MODE_AUDIT) {
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200107 ret = efi_set_variable_int(L"PK", &efi_global_variable_guid,
108 EFI_VARIABLE_BOOTSERVICE_ACCESS |
109 EFI_VARIABLE_RUNTIME_ACCESS,
110 0, NULL, false);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900111 if (ret != EFI_SUCCESS)
112 goto err;
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900113
114 ret = efi_set_secure_state(0, 1, 1, 0);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900115 if (ret != EFI_SUCCESS)
116 goto err;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900117 } else if (mode == EFI_MODE_USER) {
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900118 ret = efi_set_secure_state(1, 0, 0, 0);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900119 if (ret != EFI_SUCCESS)
120 goto err;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900121 } else if (mode == EFI_MODE_SETUP) {
AKASHI Takahirodae117a2020-04-21 09:39:20 +0900122 ret = efi_set_secure_state(0, 1, 0, 0);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900123 if (ret != EFI_SUCCESS)
124 goto err;
125 } else {
126 return EFI_INVALID_PARAMETER;
127 }
128
AKASHI Takahiro94b139a2020-04-14 11:51:43 +0900129 efi_secure_mode = mode;
130
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900131 return EFI_SUCCESS;
132
133err:
134 /* TODO: What action should be taken here? */
135 printf("ERROR: Secure state transition failed\n");
136 return ret;
137}
138
139/**
140 * efi_init_secure_state - initialize secure boot state
141 *
Heinrich Schuchardte2c43da2020-05-03 16:29:00 +0200142 * Return: status code
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900143 */
144static efi_status_t efi_init_secure_state(void)
145{
Heinrich Schuchardt6a288f72020-07-04 22:41:26 +0200146 enum efi_secure_mode mode = EFI_MODE_SETUP;
147 efi_uintn_t size = 0;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900148 efi_status_t ret;
149
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200150 ret = efi_get_variable_int(L"PK", &efi_global_variable_guid,
151 NULL, &size, NULL, NULL);
AKASHI Takahiro94b139a2020-04-14 11:51:43 +0900152 if (ret == EFI_BUFFER_TOO_SMALL) {
153 if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT))
154 mode = EFI_MODE_USER;
AKASHI Takahiro94b139a2020-04-14 11:51:43 +0900155 }
156
157 ret = efi_transfer_secure_state(mode);
Heinrich Schuchardt6a288f72020-07-04 22:41:26 +0200158 if (ret != EFI_SUCCESS)
159 return ret;
AKASHI Takahiro94b139a2020-04-14 11:51:43 +0900160
Heinrich Schuchardt6a288f72020-07-04 22:41:26 +0200161 /* As we do not provide vendor keys this variable is always 0. */
162 ret = efi_set_variable_int(L"VendorKeys",
163 &efi_global_variable_guid,
164 EFI_VARIABLE_BOOTSERVICE_ACCESS |
165 EFI_VARIABLE_RUNTIME_ACCESS |
166 EFI_VARIABLE_READ_ONLY,
167 sizeof(efi_vendor_keys),
168 &efi_vendor_keys, false);
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900169 return ret;
170}
171
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +0100172/**
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900173 * efi_secure_boot_enabled - return if secure boot is enabled or not
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +0100174 *
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900175 * Return: true if enabled, false if disabled
176 */
177bool efi_secure_boot_enabled(void)
178{
179 return efi_secure_boot;
180}
181
182#ifdef CONFIG_EFI_SECURE_BOOT
183static u8 pkcs7_hdr[] = {
184 /* SEQUENCE */
185 0x30, 0x82, 0x05, 0xc7,
186 /* OID: pkcs7-signedData */
187 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02,
188 /* Context Structured? */
189 0xa0, 0x82, 0x05, 0xb8,
190};
191
192/**
193 * efi_variable_parse_signature - parse a signature in variable
194 * @buf: Pointer to variable's value
195 * @buflen: Length of @buf
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +0100196 *
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900197 * Parse a signature embedded in variable's value and instantiate
198 * a pkcs7_message structure. Since pkcs7_parse_message() accepts only
199 * pkcs7's signedData, some header needed be prepended for correctly
200 * parsing authentication data, particularly for variable's.
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +0100201 *
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900202 * Return: Pointer to pkcs7_message structure on success, NULL on error
Heinrich Schuchardt0ffda472019-01-18 19:52:05 +0100203 */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900204static struct pkcs7_message *efi_variable_parse_signature(const void *buf,
205 size_t buflen)
206{
207 u8 *ebuf;
208 size_t ebuflen, len;
209 struct pkcs7_message *msg;
210
211 /*
212 * This is the best assumption to check if the binary is
213 * already in a form of pkcs7's signedData.
214 */
215 if (buflen > sizeof(pkcs7_hdr) &&
216 !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) {
217 msg = pkcs7_parse_message(buf, buflen);
218 goto out;
219 }
220
221 /*
222 * Otherwise, we should add a dummy prefix sequence for pkcs7
223 * message parser to be able to process.
224 * NOTE: EDK2 also uses similar hack in WrapPkcs7Data()
225 * in CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c
226 * TODO:
227 * The header should be composed in a more refined manner.
228 */
AKASHI Takahiro37123732020-06-09 14:09:34 +0900229 EFI_PRINT("Makeshift prefix added to authentication data\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900230 ebuflen = sizeof(pkcs7_hdr) + buflen;
231 if (ebuflen <= 0x7f) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900232 EFI_PRINT("Data is too short\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900233 return NULL;
234 }
235
236 ebuf = malloc(ebuflen);
237 if (!ebuf) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900238 EFI_PRINT("Out of memory\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900239 return NULL;
240 }
241
242 memcpy(ebuf, pkcs7_hdr, sizeof(pkcs7_hdr));
243 memcpy(ebuf + sizeof(pkcs7_hdr), buf, buflen);
244 len = ebuflen - 4;
245 ebuf[2] = (len >> 8) & 0xff;
246 ebuf[3] = len & 0xff;
247 len = ebuflen - 0x13;
248 ebuf[0x11] = (len >> 8) & 0xff;
249 ebuf[0x12] = len & 0xff;
250
251 msg = pkcs7_parse_message(ebuf, ebuflen);
252
253 free(ebuf);
254
255out:
256 if (IS_ERR(msg))
257 return NULL;
258
259 return msg;
260}
261
262/**
263 * efi_variable_authenticate - authenticate a variable
264 * @variable: Variable name in u16
265 * @vendor: Guid of variable
266 * @data_size: Size of @data
267 * @data: Pointer to variable's value
268 * @given_attr: Attributes to be given at SetVariable()
269 * @env_attr: Attributes that an existing variable holds
270 * @time: signed time that an existing variable holds
271 *
272 * Called by efi_set_variable() to verify that the input is correct.
273 * Will replace the given data pointer with another that points to
274 * the actual data to store in the internal memory.
275 * On success, @data and @data_size will be replaced with variable's
276 * actual data, excluding authentication data, and its size, and variable's
277 * attributes and signed time will also be returned in @env_attr and @time,
278 * respectively.
279 *
Heinrich Schuchardte2c43da2020-05-03 16:29:00 +0200280 * Return: status code
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900281 */
282static efi_status_t efi_variable_authenticate(u16 *variable,
283 const efi_guid_t *vendor,
284 efi_uintn_t *data_size,
285 const void **data, u32 given_attr,
286 u32 *env_attr, u64 *time)
287{
288 const struct efi_variable_authentication_2 *auth;
289 struct efi_signature_store *truststore, *truststore2;
290 struct pkcs7_message *var_sig;
291 struct efi_image_regions *regs;
292 struct efi_time timestamp;
293 struct rtc_time tm;
294 u64 new_time;
295 efi_status_t ret;
296
297 var_sig = NULL;
298 truststore = NULL;
299 truststore2 = NULL;
300 regs = NULL;
301 ret = EFI_SECURITY_VIOLATION;
302
303 if (*data_size < sizeof(struct efi_variable_authentication_2))
304 goto err;
305
306 /* authentication data */
307 auth = *data;
308 if (*data_size < (sizeof(auth->time_stamp)
309 + auth->auth_info.hdr.dwLength))
310 goto err;
311
312 if (guidcmp(&auth->auth_info.cert_type, &efi_guid_cert_type_pkcs7))
313 goto err;
314
Heinrich Schuchardt7a76a3f2020-07-01 12:44:00 +0200315 memcpy(&timestamp, &auth->time_stamp, sizeof(timestamp));
316 if (timestamp.pad1 || timestamp.nanosecond || timestamp.timezone ||
317 timestamp.daylight || timestamp.pad2)
318 goto err;
319
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900320 *data += sizeof(auth->time_stamp) + auth->auth_info.hdr.dwLength;
321 *data_size -= (sizeof(auth->time_stamp)
322 + auth->auth_info.hdr.dwLength);
323
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900324 memset(&tm, 0, sizeof(tm));
325 tm.tm_year = timestamp.year;
326 tm.tm_mon = timestamp.month;
327 tm.tm_mday = timestamp.day;
328 tm.tm_hour = timestamp.hour;
329 tm.tm_min = timestamp.minute;
330 tm.tm_sec = timestamp.second;
331 new_time = rtc_mktime(&tm);
332
333 if (!efi_secure_boot_enabled()) {
334 /* finished checking */
335 *time = new_time;
336 return EFI_SUCCESS;
337 }
338
339 if (new_time <= *time)
340 goto err;
341
342 /* data to be digested */
343 regs = calloc(sizeof(*regs) + sizeof(struct image_region) * 5, 1);
344 if (!regs)
345 goto err;
346 regs->max = 5;
347 efi_image_region_add(regs, (uint8_t *)variable,
348 (uint8_t *)variable
349 + u16_strlen(variable) * sizeof(u16), 1);
350 efi_image_region_add(regs, (uint8_t *)vendor,
351 (uint8_t *)vendor + sizeof(*vendor), 1);
352 efi_image_region_add(regs, (uint8_t *)&given_attr,
353 (uint8_t *)&given_attr + sizeof(given_attr), 1);
354 efi_image_region_add(regs, (uint8_t *)&timestamp,
355 (uint8_t *)&timestamp + sizeof(timestamp), 1);
356 efi_image_region_add(regs, (uint8_t *)*data,
357 (uint8_t *)*data + *data_size, 1);
358
359 /* variable's signature list */
360 if (auth->auth_info.hdr.dwLength < sizeof(auth->auth_info))
361 goto err;
362 var_sig = efi_variable_parse_signature(auth->auth_info.cert_data,
363 auth->auth_info.hdr.dwLength
364 - sizeof(auth->auth_info));
Patrick Wildtcd8a55b2020-05-07 02:13:18 +0200365 if (!var_sig) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900366 EFI_PRINT("Parsing variable's signature failed\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900367 goto err;
368 }
369
370 /* signature database used for authentication */
371 if (u16_strcmp(variable, L"PK") == 0 ||
372 u16_strcmp(variable, L"KEK") == 0) {
373 /* with PK */
374 truststore = efi_sigstore_parse_sigdb(L"PK");
375 if (!truststore)
376 goto err;
377 } else if (u16_strcmp(variable, L"db") == 0 ||
378 u16_strcmp(variable, L"dbx") == 0) {
379 /* with PK and KEK */
380 truststore = efi_sigstore_parse_sigdb(L"KEK");
381 truststore2 = efi_sigstore_parse_sigdb(L"PK");
382
383 if (!truststore) {
384 if (!truststore2)
385 goto err;
386
387 truststore = truststore2;
388 truststore2 = NULL;
389 }
390 } else {
391 /* TODO: support private authenticated variables */
392 goto err;
393 }
394
395 /* verify signature */
396 if (efi_signature_verify_with_sigdb(regs, var_sig, truststore, NULL)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900397 EFI_PRINT("Verified\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900398 } else {
399 if (truststore2 &&
400 efi_signature_verify_with_sigdb(regs, var_sig,
401 truststore2, NULL)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900402 EFI_PRINT("Verified\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900403 } else {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900404 EFI_PRINT("Verifying variable's signature failed\n");
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900405 goto err;
406 }
407 }
408
409 /* finished checking */
Heinrich Schuchardt5106dc72020-06-30 12:02:14 +0200410 *time = new_time;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900411 ret = EFI_SUCCESS;
412
413err:
414 efi_sigstore_free(truststore);
415 efi_sigstore_free(truststore2);
416 pkcs7_free_message(var_sig);
417 free(regs);
418
419 return ret;
420}
421#else
422static efi_status_t efi_variable_authenticate(u16 *variable,
423 const efi_guid_t *vendor,
424 efi_uintn_t *data_size,
425 const void **data, u32 given_attr,
426 u32 *env_attr, u64 *time)
427{
428 return EFI_SUCCESS;
429}
430#endif /* CONFIG_EFI_SECURE_BOOT */
431
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200432efi_status_t __efi_runtime
433efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
434 u32 *attributes, efi_uintn_t *data_size, void *data,
435 u64 *timep)
Rob Clark15f3d742017-09-13 18:05:37 -0400436{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200437 efi_uintn_t old_size;
438 struct efi_var_entry *var;
439 u16 *pdata;
Rob Clark15f3d742017-09-13 18:05:37 -0400440
Rob Clark15f3d742017-09-13 18:05:37 -0400441 if (!variable_name || !vendor || !data_size)
Heinrich Schuchardt563e5522020-06-29 11:49:58 +0200442 return EFI_INVALID_PARAMETER;
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200443 var = efi_var_mem_find(vendor, variable_name, NULL);
444 if (!var)
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900445 return EFI_NOT_FOUND;
Rob Clark15f3d742017-09-13 18:05:37 -0400446
Rob Clark15f3d742017-09-13 18:05:37 -0400447 if (attributes)
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200448 *attributes = var->attr;
449 if (timep)
450 *timep = var->time;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100451
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200452 old_size = *data_size;
453 *data_size = var->length;
454 if (old_size < var->length)
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100455 return EFI_BUFFER_TOO_SMALL;
Heinrich Schuchardt31d9b3a2020-03-20 19:04:34 +0100456
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200457 if (!data)
AKASHI Takahiro4854f782020-05-08 14:51:21 +0900458 return EFI_INVALID_PARAMETER;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100459
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200460 for (pdata = var->name; *pdata; ++pdata)
461 ;
462 ++pdata;
463
464 efi_memcpy_runtime(data, pdata, var->length);
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100465
466 return EFI_SUCCESS;
467}
468
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200469efi_status_t __efi_runtime
470efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
471 u16 *variable_name, efi_guid_t *vendor)
Rob Clark15f3d742017-09-13 18:05:37 -0400472{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200473 struct efi_var_entry *var;
474 efi_uintn_t old_size;
475 u16 *pdata;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100476
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100477 if (!variable_name_size || !variable_name || !vendor)
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200478 return EFI_INVALID_PARAMETER;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100479
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200480 efi_var_mem_find(vendor, variable_name, &var);
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100481
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200482 if (!var)
483 return EFI_NOT_FOUND;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100484
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200485 for (pdata = var->name; *pdata; ++pdata)
486 ;
487 ++pdata;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900488
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200489 old_size = *variable_name_size;
490 *variable_name_size = (uintptr_t)pdata - (uintptr_t)var->name;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100491
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200492 if (old_size < *variable_name_size)
493 return EFI_BUFFER_TOO_SMALL;
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100494
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200495 efi_memcpy_runtime(variable_name, var->name, *variable_name_size);
496 efi_memcpy_runtime(vendor, &var->guid, sizeof(efi_guid_t));
AKASHI Takahiroad3f36c2019-01-21 12:43:13 +0100497
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200498 return EFI_SUCCESS;
Rob Clark15f3d742017-09-13 18:05:37 -0400499}
500
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200501efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor,
502 u32 attributes, efi_uintn_t data_size,
503 const void *data, bool ro_check)
Rob Clark15f3d742017-09-13 18:05:37 -0400504{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200505 struct efi_var_entry *var;
506 efi_uintn_t ret;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900507 bool append, delete;
508 u64 time = 0;
Rob Clark15f3d742017-09-13 18:05:37 -0400509
Heinrich Schuchardtadba3962019-06-12 23:28:42 +0200510 if (!variable_name || !*variable_name || !vendor ||
511 ((attributes & EFI_VARIABLE_RUNTIME_ACCESS) &&
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200512 !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)))
513 return EFI_INVALID_PARAMETER;
Rob Clark15f3d742017-09-13 18:05:37 -0400514
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900515 /* check if a variable exists */
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200516 var = efi_var_mem_find(vendor, variable_name, NULL);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900517 append = !!(attributes & EFI_VARIABLE_APPEND_WRITE);
518 attributes &= ~(u32)EFI_VARIABLE_APPEND_WRITE;
519 delete = !append && (!data_size || !attributes);
520
521 /* check attributes */
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200522 if (var) {
523 if (ro_check && (var->attr & EFI_VARIABLE_READ_ONLY))
524 return EFI_WRITE_PROTECTED;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900525
526 /* attributes won't be changed */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900527 if (!delete &&
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200528 ((ro_check && var->attr != attributes) ||
529 (!ro_check && ((var->attr & ~(u32)EFI_VARIABLE_READ_ONLY)
Heinrich Schuchardt9827e842020-06-22 18:10:27 +0200530 != (attributes & ~(u32)EFI_VARIABLE_READ_ONLY))))) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200531 return EFI_INVALID_PARAMETER;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900532 }
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200533 time = var->time;
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900534 } else {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200535 if (delete || append)
Heinrich Schuchardt8021bbe2019-09-26 21:40:18 +0200536 /*
537 * Trying to delete or to update a non-existent
538 * variable.
539 */
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200540 return EFI_NOT_FOUND;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900541 }
AKASHI Takahiroe5023b72019-09-06 15:09:52 +0900542
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900543 if (((!u16_strcmp(variable_name, L"PK") ||
544 !u16_strcmp(variable_name, L"KEK")) &&
545 !guidcmp(vendor, &efi_global_variable_guid)) ||
546 ((!u16_strcmp(variable_name, L"db") ||
547 !u16_strcmp(variable_name, L"dbx")) &&
548 !guidcmp(vendor, &efi_guid_image_security_database))) {
549 /* authentication is mandatory */
550 if (!(attributes &
551 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200552 EFI_PRINT("%ls: TIME_BASED_AUTHENTICATED_WRITE_ACCESS required\n",
AKASHI Takahiro37123732020-06-09 14:09:34 +0900553 variable_name);
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200554 return EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900555 }
556 }
557
558 /* authenticate a variable */
559 if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200560 if (attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
561 return EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900562 if (attributes &
563 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200564 u32 env_attr;
565
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900566 ret = efi_variable_authenticate(variable_name, vendor,
567 &data_size, &data,
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200568 attributes, &env_attr,
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900569 &time);
570 if (ret != EFI_SUCCESS)
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200571 return ret;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900572
573 /* last chance to check for delete */
574 if (!data_size)
575 delete = true;
576 }
577 } else {
578 if (attributes &
579 (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS |
580 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
AKASHI Takahiro37123732020-06-09 14:09:34 +0900581 EFI_PRINT("Secure boot is not configured\n");
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200582 return EFI_INVALID_PARAMETER;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900583 }
584 }
585
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900586 if (delete) {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200587 /* EFI_NOT_FOUND has been handled before */
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900588 ret = EFI_SUCCESS;
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200589 } else if (append) {
590 u16 *old_data = var->name;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900591
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200592 for (; *old_data; ++old_data)
593 ;
594 ++old_data;
595 ret = efi_var_mem_ins(variable_name, vendor, attributes,
596 var->length, old_data, data_size, data,
597 time);
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900598 } else {
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200599 ret = efi_var_mem_ins(variable_name, vendor, attributes,
600 data_size, data, 0, NULL, time);
Rob Clark15f3d742017-09-13 18:05:37 -0400601 }
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200602 efi_var_mem_del(var);
Rob Clark15f3d742017-09-13 18:05:37 -0400603
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200604 if (ret != EFI_SUCCESS)
605 return ret;
Rob Clark15f3d742017-09-13 18:05:37 -0400606
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200607 if (!u16_strcmp(variable_name, L"PK"))
608 ret = efi_init_secure_state();
609 else
610 ret = EFI_SUCCESS;
Rob Clark15f3d742017-09-13 18:05:37 -0400611
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000612 /* Write non-volatile EFI variables to file */
613 if (attributes & EFI_VARIABLE_NON_VOLATILE &&
614 ret == EFI_SUCCESS && efi_obj_list_initialized == EFI_SUCCESS)
615 efi_var_to_file();
616
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200617 return EFI_SUCCESS;
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900618}
619
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200620efi_status_t efi_query_variable_info_int(u32 attributes,
621 u64 *maximum_variable_storage_size,
622 u64 *remaining_variable_storage_size,
623 u64 *maximum_variable_size)
624{
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200625 *maximum_variable_storage_size = EFI_VAR_BUF_SIZE -
626 sizeof(struct efi_var_file);
627 *remaining_variable_storage_size = efi_var_mem_free();
628 *maximum_variable_size = EFI_VAR_BUF_SIZE -
629 sizeof(struct efi_var_file) -
630 sizeof(struct efi_var_entry);
631 return EFI_SUCCESS;
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200632}
633
AKASHI Takahirob0f49ee2020-04-14 11:51:41 +0900634/**
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200635 * efi_query_variable_info_runtime() - runtime implementation of
636 * QueryVariableInfo()
Heinrich Schuchardt9b19dae2019-06-20 12:13:05 +0200637 *
638 * @attributes: bitmask to select variables to be
639 * queried
640 * @maximum_variable_storage_size: maximum size of storage area for the
641 * selected variable types
642 * @remaining_variable_storage_size: remaining size of storage are for the
643 * selected variable types
644 * @maximum_variable_size: maximum size of a variable of the
645 * selected type
646 * Returns: status code
647 */
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200648efi_status_t __efi_runtime EFIAPI efi_query_variable_info_runtime(
Heinrich Schuchardt9b19dae2019-06-20 12:13:05 +0200649 u32 attributes,
650 u64 *maximum_variable_storage_size,
651 u64 *remaining_variable_storage_size,
652 u64 *maximum_variable_size)
653{
654 return EFI_UNSUPPORTED;
655}
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +0200656
657/**
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200658 * efi_get_variable_runtime() - runtime implementation of GetVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +0200659 *
660 * @variable_name: name of the variable
661 * @vendor: vendor GUID
662 * @attributes: attributes of the variable
663 * @data_size: size of the buffer to which the variable value is copied
664 * @data: buffer to which the variable value is copied
665 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200666 */
667static efi_status_t __efi_runtime EFIAPI
668efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
669 u32 *attributes, efi_uintn_t *data_size, void *data)
670{
671 return EFI_UNSUPPORTED;
672}
673
674/**
675 * efi_get_next_variable_name_runtime() - runtime implementation of
676 * GetNextVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +0200677 *
678 * @variable_name_size: size of variable_name buffer in byte
679 * @variable_name: name of uefi variable's name in u16
680 * @vendor: vendor's guid
681 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200682 */
683static efi_status_t __efi_runtime EFIAPI
684efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
Heinrich Schuchardt82cd6c42020-03-22 18:28:20 +0100685 u16 *variable_name, efi_guid_t *vendor)
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200686{
687 return EFI_UNSUPPORTED;
688}
689
690/**
691 * efi_set_variable_runtime() - runtime implementation of SetVariable()
Heinrich Schuchardtee1f0e42019-07-14 12:11:16 +0200692 *
693 * @variable_name: name of the variable
694 * @vendor: vendor GUID
695 * @attributes: attributes of the variable
696 * @data_size: size of the buffer with the variable value
697 * @data: buffer with the variable value
698 * Return: status code
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200699 */
700static efi_status_t __efi_runtime EFIAPI
701efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
702 u32 attributes, efi_uintn_t data_size,
703 const void *data)
704{
705 return EFI_UNSUPPORTED;
706}
707
708/**
709 * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
710 */
711void efi_variables_boot_exit_notify(void)
712{
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000713 /* Switch variable services functions to runtime version */
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200714 efi_runtime_services.get_variable = efi_get_variable_runtime;
715 efi_runtime_services.get_next_variable_name =
716 efi_get_next_variable_name_runtime;
717 efi_runtime_services.set_variable = efi_set_variable_runtime;
Heinrich Schuchardt276c61d2020-06-26 17:57:48 +0200718 efi_runtime_services.query_variable_info =
719 efi_query_variable_info_runtime;
Heinrich Schuchardt2ac62582019-06-20 15:25:48 +0200720 efi_update_table_header_crc32(&efi_runtime_services.hdr);
721}
722
723/**
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +0200724 * efi_init_variables() - initialize variable services
725 *
726 * Return: status code
727 */
728efi_status_t efi_init_variables(void)
729{
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900730 efi_status_t ret;
731
Heinrich Schuchardt047276c2020-07-04 18:34:15 +0200732 ret = efi_var_mem_init();
733 if (ret != EFI_SUCCESS)
734 return ret;
735
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900736 ret = efi_init_secure_state();
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000737 if (ret != EFI_SUCCESS)
738 return ret;
AKASHI Takahiroc78dc192020-04-14 11:51:42 +0900739
Heinrich Schuchardt09a8d502020-03-19 18:21:58 +0000740 return efi_var_from_file();
Heinrich Schuchardtcf3b1182019-06-20 13:52:16 +0200741}