• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  EFI utils
4  *
5  *  Copyright (c) 2017 Rob Clark
6  */
7 
8 #include <common.h>
9 #include <efi_loader.h>
10 #include <env_internal.h>
11 #include <hexdump.h>
12 #include <malloc.h>
13 #include <search.h>
14 #include <u-boot/crc.h>
15 
16 #define READ_ONLY BIT(31)
17 
18 /*
19  * Mapping between EFI variables and u-boot variables:
20  *
21  *   efi_$guid_$varname = {attributes}(type)value
22  *
23  * For example:
24  *
25  *   efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported=
26  *      "{ro,boot,run}(blob)0000000000000000"
27  *   efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder=
28  *      "(blob)00010000"
29  *
30  * The attributes are a comma separated list of these possible
31  * attributes:
32  *
33  *   + ro   - read-only
34  *   + boot - boot-services access
35  *   + run  - runtime access
36  *
37  * NOTE: with current implementation, no variables are available after
38  * ExitBootServices, and all are persisted (if possible).
39  *
40  * If not specified, the attributes default to "{boot}".
41  *
42  * The required type is one of:
43  *
44  *   + utf8 - raw utf8 string
45  *   + blob - arbitrary length hex string
46  *
47  * Maybe a utf16 type would be useful to for a string value to be auto
48  * converted to utf16?
49  */
50 
51 #define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_"))
52 
53 /**
54  * efi_to_native() - convert the UEFI variable name and vendor GUID to U-Boot
55  *		     variable name
56  *
57  * The U-Boot variable name is a concatenation of prefix 'efi', the hexstring
58  * encoded vendor GUID, and the UTF-8 encoded UEFI variable name separated by
59  * underscores, e.g. 'efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder'.
60  *
61  * @native:		pointer to pointer to U-Boot variable name
62  * @variable_name:	UEFI variable name
63  * @vendor:		vendor GUID
64  * Return:		status code
65  */
efi_to_native(char ** native,const u16 * variable_name,const efi_guid_t * vendor)66 static efi_status_t efi_to_native(char **native, const u16 *variable_name,
67 				  const efi_guid_t *vendor)
68 {
69 	size_t len;
70 	char *pos;
71 
72 	len = PREFIX_LEN + utf16_utf8_strlen(variable_name) + 1;
73 	*native = malloc(len);
74 	if (!*native)
75 		return EFI_OUT_OF_RESOURCES;
76 
77 	pos = *native;
78 	pos += sprintf(pos, "efi_%pUl_", vendor);
79 	utf16_utf8_strcpy(&pos, variable_name);
80 
81 	return EFI_SUCCESS;
82 }
83 
84 /**
85  * prefix() - skip over prefix
86  *
87  * Skip over a prefix string.
88  *
89  * @str:	string with prefix
90  * @prefix:	prefix string
91  * Return:	string without prefix, or NULL if prefix not found
92  */
prefix(const char * str,const char * prefix)93 static const char *prefix(const char *str, const char *prefix)
94 {
95 	size_t n = strlen(prefix);
96 	if (!strncmp(prefix, str, n))
97 		return str + n;
98 	return NULL;
99 }
100 
101 /**
102  * parse_attr() - decode attributes part of variable value
103  *
104  * Convert the string encoded attributes of a UEFI variable to a bit mask.
105  * TODO: Several attributes are not supported.
106  *
107  * @str:	value of U-Boot variable
108  * @attrp:	pointer to UEFI attributes
109  * Return:	pointer to remainder of U-Boot variable value
110  */
parse_attr(const char * str,u32 * attrp)111 static const char *parse_attr(const char *str, u32 *attrp)
112 {
113 	u32 attr = 0;
114 	char sep = '{';
115 
116 	if (*str != '{') {
117 		*attrp = EFI_VARIABLE_BOOTSERVICE_ACCESS;
118 		return str;
119 	}
120 
121 	while (*str == sep) {
122 		const char *s;
123 
124 		str++;
125 
126 		if ((s = prefix(str, "ro"))) {
127 			attr |= READ_ONLY;
128 		} else if ((s = prefix(str, "nv"))) {
129 			attr |= EFI_VARIABLE_NON_VOLATILE;
130 		} else if ((s = prefix(str, "boot"))) {
131 			attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS;
132 		} else if ((s = prefix(str, "run"))) {
133 			attr |= EFI_VARIABLE_RUNTIME_ACCESS;
134 		} else {
135 			printf("invalid attribute: %s\n", str);
136 			break;
137 		}
138 
139 		str = s;
140 		sep = ',';
141 	}
142 
143 	str++;
144 
145 	*attrp = attr;
146 
147 	return str;
148 }
149 
150 /**
151  * efi_get_variable() - retrieve value of a UEFI variable
152  *
153  * This function implements the GetVariable runtime service.
154  *
155  * See the Unified Extensible Firmware Interface (UEFI) specification for
156  * details.
157  *
158  * @variable_name:	name of the variable
159  * @vendor:		vendor GUID
160  * @attributes:		attributes of the variable
161  * @data_size:		size of the buffer to which the variable value is copied
162  * @data:		buffer to which the variable value is copied
163  * Return:		status code
164  */
efi_get_variable(u16 * variable_name,const efi_guid_t * vendor,u32 * attributes,efi_uintn_t * data_size,void * data)165 efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
166 				     const efi_guid_t *vendor, u32 *attributes,
167 				     efi_uintn_t *data_size, void *data)
168 {
169 	char *native_name;
170 	efi_status_t ret;
171 	unsigned long in_size;
172 	const char *val, *s;
173 	u32 attr;
174 
175 	EFI_ENTRY("\"%ls\" %pUl %p %p %p", variable_name, vendor, attributes,
176 		  data_size, data);
177 
178 	if (!variable_name || !vendor || !data_size)
179 		return EFI_EXIT(EFI_INVALID_PARAMETER);
180 
181 	ret = efi_to_native(&native_name, variable_name, vendor);
182 	if (ret)
183 		return EFI_EXIT(ret);
184 
185 	EFI_PRINT("get '%s'\n", native_name);
186 
187 	val = env_get(native_name);
188 	free(native_name);
189 	if (!val)
190 		return EFI_EXIT(EFI_NOT_FOUND);
191 
192 	val = parse_attr(val, &attr);
193 
194 	in_size = *data_size;
195 
196 	if ((s = prefix(val, "(blob)"))) {
197 		size_t len = strlen(s);
198 
199 		/* number of hexadecimal digits must be even */
200 		if (len & 1)
201 			return EFI_EXIT(EFI_DEVICE_ERROR);
202 
203 		/* two characters per byte: */
204 		len /= 2;
205 		*data_size = len;
206 
207 		if (in_size < len) {
208 			ret = EFI_BUFFER_TOO_SMALL;
209 			goto out;
210 		}
211 
212 		if (!data)
213 			return EFI_EXIT(EFI_INVALID_PARAMETER);
214 
215 		if (hex2bin(data, s, len))
216 			return EFI_EXIT(EFI_DEVICE_ERROR);
217 
218 		EFI_PRINT("got value: \"%s\"\n", s);
219 	} else if ((s = prefix(val, "(utf8)"))) {
220 		unsigned len = strlen(s) + 1;
221 
222 		*data_size = len;
223 
224 		if (in_size < len) {
225 			ret = EFI_BUFFER_TOO_SMALL;
226 			goto out;
227 		}
228 
229 		if (!data)
230 			return EFI_EXIT(EFI_INVALID_PARAMETER);
231 
232 		memcpy(data, s, len);
233 		((char *)data)[len] = '\0';
234 
235 		EFI_PRINT("got value: \"%s\"\n", (char *)data);
236 	} else {
237 		EFI_PRINT("invalid value: '%s'\n", val);
238 		return EFI_EXIT(EFI_DEVICE_ERROR);
239 	}
240 
241 out:
242 	if (attributes)
243 		*attributes = attr & EFI_VARIABLE_MASK;
244 
245 	return EFI_EXIT(ret);
246 }
247 
248 static char *efi_variables_list;
249 static char *efi_cur_variable;
250 
251 /**
252  * parse_uboot_variable() - parse a u-boot variable and get uefi-related
253  *			    information
254  * @variable:		whole data of u-boot variable (ie. name=value)
255  * @variable_name_size: size of variable_name buffer in byte
256  * @variable_name:	name of uefi variable in u16, null-terminated
257  * @vendor:		vendor's guid
258  * @attributes:		attributes
259  *
260  * A uefi variable is encoded into a u-boot variable as described above.
261  * This function parses such a u-boot variable and retrieve uefi-related
262  * information into respective parameters. In return, variable_name_size
263  * is the size of variable name including NULL.
264  *
265  * Return:		EFI_SUCCESS if parsing is OK, EFI_NOT_FOUND when
266  *			the entire variable list has been returned,
267  *			otherwise non-zero status code
268  */
parse_uboot_variable(char * variable,efi_uintn_t * variable_name_size,u16 * variable_name,const efi_guid_t * vendor,u32 * attributes)269 static efi_status_t parse_uboot_variable(char *variable,
270 					 efi_uintn_t *variable_name_size,
271 					 u16 *variable_name,
272 					 const efi_guid_t *vendor,
273 					 u32 *attributes)
274 {
275 	char *guid, *name, *end, c;
276 	unsigned long name_len;
277 	u16 *p;
278 
279 	guid = strchr(variable, '_');
280 	if (!guid)
281 		return EFI_INVALID_PARAMETER;
282 	guid++;
283 	name = strchr(guid, '_');
284 	if (!name)
285 		return EFI_INVALID_PARAMETER;
286 	name++;
287 	end = strchr(name, '=');
288 	if (!end)
289 		return EFI_INVALID_PARAMETER;
290 
291 	name_len = end - name;
292 	if (*variable_name_size < (name_len + 1)) {
293 		*variable_name_size = name_len + 1;
294 		return EFI_BUFFER_TOO_SMALL;
295 	}
296 	end++; /* point to value */
297 
298 	/* variable name */
299 	p = variable_name;
300 	utf8_utf16_strncpy(&p, name, name_len);
301 	variable_name[name_len] = 0;
302 	*variable_name_size = name_len + 1;
303 
304 	/* guid */
305 	c = *(name - 1);
306 	*(name - 1) = '\0'; /* guid need be null-terminated here */
307 	uuid_str_to_bin(guid, (unsigned char *)vendor, UUID_STR_FORMAT_GUID);
308 	*(name - 1) = c;
309 
310 	/* attributes */
311 	parse_attr(end, attributes);
312 
313 	return EFI_SUCCESS;
314 }
315 
316 /**
317  * efi_get_next_variable_name() - enumerate the current variable names
318  *
319  * @variable_name_size:	size of variable_name buffer in byte
320  * @variable_name:	name of uefi variable's name in u16
321  * @vendor:		vendor's guid
322  *
323  * This function implements the GetNextVariableName service.
324  *
325  * See the Unified Extensible Firmware Interface (UEFI) specification for
326  * details.
327  *
328  * Return: status code
329  */
efi_get_next_variable_name(efi_uintn_t * variable_name_size,u16 * variable_name,const efi_guid_t * vendor)330 efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size,
331 					       u16 *variable_name,
332 					       const efi_guid_t *vendor)
333 {
334 	char *native_name, *variable;
335 	ssize_t name_len, list_len;
336 	char regex[256];
337 	char * const regexlist[] = {regex};
338 	u32 attributes;
339 	int i;
340 	efi_status_t ret;
341 
342 	EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, vendor);
343 
344 	if (!variable_name_size || !variable_name || !vendor)
345 		return EFI_EXIT(EFI_INVALID_PARAMETER);
346 
347 	if (variable_name[0]) {
348 		/* check null-terminated string */
349 		for (i = 0; i < *variable_name_size; i++)
350 			if (!variable_name[i])
351 				break;
352 		if (i >= *variable_name_size)
353 			return EFI_EXIT(EFI_INVALID_PARAMETER);
354 
355 		/* search for the last-returned variable */
356 		ret = efi_to_native(&native_name, variable_name, vendor);
357 		if (ret)
358 			return EFI_EXIT(ret);
359 
360 		name_len = strlen(native_name);
361 		for (variable = efi_variables_list; variable && *variable;) {
362 			if (!strncmp(variable, native_name, name_len) &&
363 			    variable[name_len] == '=')
364 				break;
365 
366 			variable = strchr(variable, '\n');
367 			if (variable)
368 				variable++;
369 		}
370 
371 		free(native_name);
372 		if (!(variable && *variable))
373 			return EFI_EXIT(EFI_INVALID_PARAMETER);
374 
375 		/* next variable */
376 		variable = strchr(variable, '\n');
377 		if (variable)
378 			variable++;
379 		if (!(variable && *variable))
380 			return EFI_EXIT(EFI_NOT_FOUND);
381 	} else {
382 		/*
383 		 *new search: free a list used in the previous search
384 		 */
385 		free(efi_variables_list);
386 		efi_variables_list = NULL;
387 		efi_cur_variable = NULL;
388 
389 		snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_.*");
390 		list_len = hexport_r(&env_htab, '\n',
391 				     H_MATCH_REGEX | H_MATCH_KEY,
392 				     &efi_variables_list, 0, 1, regexlist);
393 		/* 1 indicates that no match was found */
394 		if (list_len <= 1)
395 			return EFI_EXIT(EFI_NOT_FOUND);
396 
397 		variable = efi_variables_list;
398 	}
399 
400 	ret = parse_uboot_variable(variable, variable_name_size, variable_name,
401 				   vendor, &attributes);
402 
403 	return EFI_EXIT(ret);
404 }
405 
406 /**
407  * efi_set_variable() - set value of a UEFI variable
408  *
409  * This function implements the SetVariable runtime service.
410  *
411  * See the Unified Extensible Firmware Interface (UEFI) specification for
412  * details.
413  *
414  * @variable_name:	name of the variable
415  * @vendor:		vendor GUID
416  * @attributes:		attributes of the variable
417  * @data_size:		size of the buffer with the variable value
418  * @data:		buffer with the variable value
419  * Return:		status code
420  */
efi_set_variable(u16 * variable_name,const efi_guid_t * vendor,u32 attributes,efi_uintn_t data_size,const void * data)421 efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
422 				     const efi_guid_t *vendor, u32 attributes,
423 				     efi_uintn_t data_size, const void *data)
424 {
425 	char *native_name = NULL, *val = NULL, *s;
426 	const char *old_val;
427 	size_t old_size;
428 	efi_status_t ret = EFI_SUCCESS;
429 	u32 attr;
430 
431 	EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes,
432 		  data_size, data);
433 
434 	if (!variable_name || !*variable_name || !vendor ||
435 	    ((attributes & EFI_VARIABLE_RUNTIME_ACCESS) &&
436 	     !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS))) {
437 		ret = EFI_INVALID_PARAMETER;
438 		goto out;
439 	}
440 
441 	ret = efi_to_native(&native_name, variable_name, vendor);
442 	if (ret)
443 		goto out;
444 
445 	old_val = env_get(native_name);
446 	if (old_val) {
447 		old_val = parse_attr(old_val, &attr);
448 
449 		/* check read-only first */
450 		if (attr & READ_ONLY) {
451 			ret = EFI_WRITE_PROTECTED;
452 			goto out;
453 		}
454 
455 		if ((data_size == 0 &&
456 		     !(attributes & EFI_VARIABLE_APPEND_WRITE)) ||
457 		    !attributes) {
458 			/* delete the variable: */
459 			env_set(native_name, NULL);
460 			ret = EFI_SUCCESS;
461 			goto out;
462 		}
463 
464 		/* attributes won't be changed */
465 		if (attr != (attributes & ~EFI_VARIABLE_APPEND_WRITE)) {
466 			ret = EFI_INVALID_PARAMETER;
467 			goto out;
468 		}
469 
470 		if (attributes & EFI_VARIABLE_APPEND_WRITE) {
471 			if (!prefix(old_val, "(blob)")) {
472 				ret = EFI_DEVICE_ERROR;
473 				goto out;
474 			}
475 			old_size = strlen(old_val);
476 		} else {
477 			old_size = 0;
478 		}
479 	} else {
480 		if (data_size == 0 || !attributes ||
481 		    (attributes & EFI_VARIABLE_APPEND_WRITE)) {
482 			/*
483 			 * Trying to delete or to update a non-existent
484 			 * variable.
485 			 */
486 			ret = EFI_NOT_FOUND;
487 			goto out;
488 		}
489 
490 		old_size = 0;
491 	}
492 
493 	val = malloc(old_size + 2 * data_size
494 		     + strlen("{ro,run,boot,nv}(blob)") + 1);
495 	if (!val) {
496 		ret = EFI_OUT_OF_RESOURCES;
497 		goto out;
498 	}
499 
500 	s = val;
501 
502 	/* store attributes */
503 	attributes &= (EFI_VARIABLE_NON_VOLATILE |
504 		       EFI_VARIABLE_BOOTSERVICE_ACCESS |
505 		       EFI_VARIABLE_RUNTIME_ACCESS);
506 	s += sprintf(s, "{");
507 	while (attributes) {
508 		u32 attr = 1 << (ffs(attributes) - 1);
509 
510 		if (attr == EFI_VARIABLE_NON_VOLATILE)
511 			s += sprintf(s, "nv");
512 		else if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS)
513 			s += sprintf(s, "boot");
514 		else if (attr == EFI_VARIABLE_RUNTIME_ACCESS)
515 			s += sprintf(s, "run");
516 
517 		attributes &= ~attr;
518 		if (attributes)
519 			s += sprintf(s, ",");
520 	}
521 	s += sprintf(s, "}");
522 
523 	if (old_size)
524 		/* APPEND_WRITE */
525 		s += sprintf(s, old_val);
526 	else
527 		s += sprintf(s, "(blob)");
528 
529 	/* store payload: */
530 	s = bin2hex(s, data, data_size);
531 	*s = '\0';
532 
533 	EFI_PRINT("setting: %s=%s\n", native_name, val);
534 
535 	if (env_set(native_name, val))
536 		ret = EFI_DEVICE_ERROR;
537 
538 out:
539 	free(native_name);
540 	free(val);
541 
542 	return EFI_EXIT(ret);
543 }
544 
545 /**
546  * efi_query_variable_info() - get information about EFI variables
547  *
548  * This function implements the QueryVariableInfo() runtime service.
549  *
550  * See the Unified Extensible Firmware Interface (UEFI) specification for
551  * details.
552  *
553  * @attributes:				bitmask to select variables to be
554  *					queried
555  * @maximum_variable_storage_size:	maximum size of storage area for the
556  *					selected variable types
557  * @remaining_variable_storage_size:	remaining size of storage are for the
558  *					selected variable types
559  * @maximum_variable_size:		maximum size of a variable of the
560  *					selected type
561  * Returns:				status code
562  */
efi_query_variable_info(u32 attributes,u64 * maximum_variable_storage_size,u64 * remaining_variable_storage_size,u64 * maximum_variable_size)563 efi_status_t __efi_runtime EFIAPI efi_query_variable_info(
564 			u32 attributes,
565 			u64 *maximum_variable_storage_size,
566 			u64 *remaining_variable_storage_size,
567 			u64 *maximum_variable_size)
568 {
569 	return EFI_UNSUPPORTED;
570 }
571 
572 /**
573  * efi_get_variable_runtime() - runtime implementation of GetVariable()
574  *
575  * @variable_name:	name of the variable
576  * @vendor:		vendor GUID
577  * @attributes:		attributes of the variable
578  * @data_size:		size of the buffer to which the variable value is copied
579  * @data:		buffer to which the variable value is copied
580  * Return:		status code
581  */
582 static efi_status_t __efi_runtime EFIAPI
efi_get_variable_runtime(u16 * variable_name,const efi_guid_t * vendor,u32 * attributes,efi_uintn_t * data_size,void * data)583 efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
584 			 u32 *attributes, efi_uintn_t *data_size, void *data)
585 {
586 	return EFI_UNSUPPORTED;
587 }
588 
589 /**
590  * efi_get_next_variable_name_runtime() - runtime implementation of
591  *					  GetNextVariable()
592  *
593  * @variable_name_size:	size of variable_name buffer in byte
594  * @variable_name:	name of uefi variable's name in u16
595  * @vendor:		vendor's guid
596  * Return: status code
597  */
598 static efi_status_t __efi_runtime EFIAPI
efi_get_next_variable_name_runtime(efi_uintn_t * variable_name_size,u16 * variable_name,const efi_guid_t * vendor)599 efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
600 				   u16 *variable_name, const efi_guid_t *vendor)
601 {
602 	return EFI_UNSUPPORTED;
603 }
604 
605 /**
606  * efi_set_variable_runtime() - runtime implementation of SetVariable()
607  *
608  * @variable_name:	name of the variable
609  * @vendor:		vendor GUID
610  * @attributes:		attributes of the variable
611  * @data_size:		size of the buffer with the variable value
612  * @data:		buffer with the variable value
613  * Return:		status code
614  */
615 static efi_status_t __efi_runtime EFIAPI
efi_set_variable_runtime(u16 * variable_name,const efi_guid_t * vendor,u32 attributes,efi_uintn_t data_size,const void * data)616 efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
617 			 u32 attributes, efi_uintn_t data_size,
618 			 const void *data)
619 {
620 	return EFI_UNSUPPORTED;
621 }
622 
623 /**
624  * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
625  */
efi_variables_boot_exit_notify(void)626 void efi_variables_boot_exit_notify(void)
627 {
628 	efi_runtime_services.get_variable = efi_get_variable_runtime;
629 	efi_runtime_services.get_next_variable_name =
630 				efi_get_next_variable_name_runtime;
631 	efi_runtime_services.set_variable = efi_set_variable_runtime;
632 	efi_update_table_header_crc32(&efi_runtime_services.hdr);
633 }
634 
635 /**
636  * efi_init_variables() - initialize variable services
637  *
638  * Return:	status code
639  */
efi_init_variables(void)640 efi_status_t efi_init_variables(void)
641 {
642 	return EFI_SUCCESS;
643 }
644