xref: /freebsd/usr.sbin/efivar/efiutil.c (revision 1d386b48)
15709a4b5SWarner Losh /*-
2748f247aSRebecca Cran  * Copyright (c) 2017-2019 Netflix, Inc.
35709a4b5SWarner Losh  *
45709a4b5SWarner Losh  * Redistribution and use in source and binary forms, with or without
55709a4b5SWarner Losh  * modification, are permitted provided that the following conditions
65709a4b5SWarner Losh  * are met:
75709a4b5SWarner Losh  * 1. Redistributions of source code must retain the above copyright
85709a4b5SWarner Losh  *    notice, this list of conditions and the following disclaimer.
95709a4b5SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
105709a4b5SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
115709a4b5SWarner Losh  *    documentation and/or other materials provided with the distribution.
125709a4b5SWarner Losh  *
135709a4b5SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
145709a4b5SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
155709a4b5SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
165709a4b5SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
175709a4b5SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
185709a4b5SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
195709a4b5SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
205709a4b5SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
215709a4b5SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
225709a4b5SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
235709a4b5SWarner Losh  * SUCH DAMAGE.
245709a4b5SWarner Losh  */
255709a4b5SWarner Losh 
265709a4b5SWarner Losh #include <sys/cdefs.h>
275709a4b5SWarner Losh #include <ctype.h>
285709a4b5SWarner Losh #include <efivar.h>
295709a4b5SWarner Losh #include <efivar-dp.h>
305709a4b5SWarner Losh #include <err.h>
315709a4b5SWarner Losh #include <errno.h>
325709a4b5SWarner Losh #include <getopt.h>
335709a4b5SWarner Losh #include <stddef.h>
345709a4b5SWarner Losh #include <stdio.h>
355709a4b5SWarner Losh #include <stdlib.h>
365709a4b5SWarner Losh #include <string.h>
375709a4b5SWarner Losh #include <unistd.h>
385709a4b5SWarner Losh #include "efiutil.h"
395709a4b5SWarner Losh #include "efichar.h"
405709a4b5SWarner Losh #include <efivar-dp.h>
415709a4b5SWarner Losh 
425709a4b5SWarner Losh /*
435709a4b5SWarner Losh  * Dump the data as ASCII data, which is a pretty
445709a4b5SWarner Losh  * printed form
455709a4b5SWarner Losh  */
465709a4b5SWarner Losh void
asciidump(uint8_t * data,size_t datalen)475709a4b5SWarner Losh asciidump(uint8_t *data, size_t datalen)
485709a4b5SWarner Losh {
495709a4b5SWarner Losh 	size_t i;
505709a4b5SWarner Losh 	int len;
515709a4b5SWarner Losh 
525709a4b5SWarner Losh 	len = 0;
535709a4b5SWarner Losh 	for (i = 0; i < datalen; i++) {
545709a4b5SWarner Losh 		if (isprint(data[i])) {
555709a4b5SWarner Losh 			len++;
565709a4b5SWarner Losh 			if (len > 80) {
575709a4b5SWarner Losh 				len = 0;
585709a4b5SWarner Losh 				printf("\n");
595709a4b5SWarner Losh 			}
605709a4b5SWarner Losh 			printf("%c", data[i]);
615709a4b5SWarner Losh 		} else {
625709a4b5SWarner Losh 			len +=3;
635709a4b5SWarner Losh 			if (len > 80) {
645709a4b5SWarner Losh 				len = 0;
655709a4b5SWarner Losh 				printf("\n");
665709a4b5SWarner Losh 			}
675709a4b5SWarner Losh 			printf("%%%02x", data[i]);
685709a4b5SWarner Losh 		}
695709a4b5SWarner Losh 	}
705709a4b5SWarner Losh 	printf("\n");
715709a4b5SWarner Losh }
725709a4b5SWarner Losh 
735709a4b5SWarner Losh void
utf8dump(uint8_t * data,size_t datalen)745709a4b5SWarner Losh utf8dump(uint8_t *data, size_t datalen)
755709a4b5SWarner Losh {
765709a4b5SWarner Losh 	char *utf8 = NULL;
775709a4b5SWarner Losh 	efi_char *ucs2;
785709a4b5SWarner Losh 
795709a4b5SWarner Losh 	/*
805709a4b5SWarner Losh 	 * NUL terminate the string. Not all strings need it, but some
815709a4b5SWarner Losh 	 * do and an extra NUL won't change what's printed.
825709a4b5SWarner Losh 	 */
835709a4b5SWarner Losh 	ucs2 = malloc(datalen + sizeof(efi_char));
845709a4b5SWarner Losh 	memcpy(ucs2, data, datalen);
855709a4b5SWarner Losh 	ucs2[datalen / sizeof(efi_char)] = 0;
865709a4b5SWarner Losh 	ucs2_to_utf8(ucs2, &utf8);
875709a4b5SWarner Losh 	printf("%s\n", utf8);
885709a4b5SWarner Losh 	free(utf8);
895709a4b5SWarner Losh 	free(ucs2);
905709a4b5SWarner Losh }
915709a4b5SWarner Losh 
925709a4b5SWarner Losh void
hexdump(uint8_t * data,size_t datalen)935709a4b5SWarner Losh hexdump(uint8_t *data, size_t datalen)
945709a4b5SWarner Losh {
955709a4b5SWarner Losh 	size_t i;
965709a4b5SWarner Losh 
975709a4b5SWarner Losh 	for (i = 0; i < datalen; i++) {
985709a4b5SWarner Losh 		if (i % 16 == 0) {
995709a4b5SWarner Losh 			if (i != 0)
1005709a4b5SWarner Losh 				printf("\n");
1015709a4b5SWarner Losh 			printf("%04x: ", (int)i);
1025709a4b5SWarner Losh 		}
1035709a4b5SWarner Losh 		printf("%02x ", data[i]);
1045709a4b5SWarner Losh 	}
1055709a4b5SWarner Losh 	printf("\n");
1065709a4b5SWarner Losh }
1075709a4b5SWarner Losh 
1085709a4b5SWarner Losh void
bindump(uint8_t * data,size_t datalen)1095709a4b5SWarner Losh bindump(uint8_t *data, size_t datalen)
1105709a4b5SWarner Losh {
1115709a4b5SWarner Losh 	write(1, data, datalen);
1125709a4b5SWarner Losh }
1135709a4b5SWarner Losh 
1145709a4b5SWarner Losh #define LOAD_OPTION_ACTIVE 1
1155709a4b5SWarner Losh 
11692f9212bSWarner Losh #define SIZE(dp, edp) (size_t)((intptr_t)(void *)edp - (intptr_t)(void *)dp)
11792f9212bSWarner Losh 
1185709a4b5SWarner Losh void
efi_print_load_option(uint8_t * data,size_t datalen,int Aflag,int bflag,int uflag)1195709a4b5SWarner Losh efi_print_load_option(uint8_t *data, size_t datalen, int Aflag, int bflag, int uflag)
1205709a4b5SWarner Losh {
121748f247aSRebecca Cran 	char *dev, *relpath, *abspath;
1225709a4b5SWarner Losh 	uint8_t *ep = data + datalen;
1235709a4b5SWarner Losh 	uint8_t *walker = data;
1245709a4b5SWarner Losh 	uint32_t attr;
1255709a4b5SWarner Losh 	uint16_t fplen;
1265709a4b5SWarner Losh 	efi_char *descr;
1275709a4b5SWarner Losh 	efidp dp, edp;
12896723f5aSWarner Losh 	char *str = NULL;
1295709a4b5SWarner Losh 	char buf[1024];
1305709a4b5SWarner Losh 	int len;
1315709a4b5SWarner Losh 	void *opt;
1325709a4b5SWarner Losh 	int optlen;
133748f247aSRebecca Cran 	int rv;
1345709a4b5SWarner Losh 
1355709a4b5SWarner Losh 	if (datalen < sizeof(attr) + sizeof(fplen) + sizeof(efi_char))
1365709a4b5SWarner Losh 		return;
1375709a4b5SWarner Losh 	// First 4 bytes are attribute flags
1385709a4b5SWarner Losh 	attr = le32dec(walker);
1395709a4b5SWarner Losh 	walker += sizeof(attr);
1405709a4b5SWarner Losh 	// Next two bytes are length of the file paths
1415709a4b5SWarner Losh 	fplen = le16dec(walker);
1425709a4b5SWarner Losh 	walker += sizeof(fplen);
1435709a4b5SWarner Losh 	// Next we have a 0 terminated UCS2 string that we know to be aligned
1445709a4b5SWarner Losh 	descr = (efi_char *)(intptr_t)(void *)walker;
1455709a4b5SWarner Losh 	len = ucs2len(descr); // XXX need to sanity check that len < (datalen - (ep - walker) / 2)
1465709a4b5SWarner Losh 	walker += (len + 1) * sizeof(efi_char);
1475709a4b5SWarner Losh 	if (walker > ep)
1485709a4b5SWarner Losh 		return;
1495709a4b5SWarner Losh 	// Now we have fplen bytes worth of file path stuff
1505709a4b5SWarner Losh 	dp = (efidp)walker;
1515709a4b5SWarner Losh 	walker += fplen;
1525709a4b5SWarner Losh 	if (walker > ep)
1535709a4b5SWarner Losh 		return;
1545709a4b5SWarner Losh 	edp = (efidp)walker;
1555709a4b5SWarner Losh 	// Everything left is the binary option args
1565709a4b5SWarner Losh 	opt = walker;
1575709a4b5SWarner Losh 	optlen = ep - walker;
1585709a4b5SWarner Losh 	// We got to here, everything is good
1595709a4b5SWarner Losh 	printf("%c ", attr & LOAD_OPTION_ACTIVE ? '*' : ' ');
1605709a4b5SWarner Losh 	ucs2_to_utf8(descr, &str);
16166c61390SWarner Losh 	printf("%s\n", str);
1625709a4b5SWarner Losh 	free(str);
16366c61390SWarner Losh 	if (fplen <= 4) {
16466c61390SWarner Losh 		printf("Empty path\n");
16566c61390SWarner Losh 	} else {
16692f9212bSWarner Losh 		while (dp < edp && SIZE(dp, edp) > sizeof(efidp_header)) {
16792f9212bSWarner Losh 			efidp_format_device_path(buf, sizeof(buf), dp, SIZE(dp, edp));
168748f247aSRebecca Cran 			rv = efivar_device_path_to_unix_path(dp, &dev, &relpath, &abspath);
1695709a4b5SWarner Losh 			dp = (efidp)((char *)dp + efidp_size(dp));
1705709a4b5SWarner Losh 			printf(" %s\n", buf);
171748f247aSRebecca Cran 			if (rv == 0) {
172748f247aSRebecca Cran 				printf("      %*s:%s\n", len + (int)strlen(dev), dev, relpath);
173748f247aSRebecca Cran 				free(dev);
174748f247aSRebecca Cran 				free(relpath);
175748f247aSRebecca Cran 				free(abspath);
176748f247aSRebecca Cran 			}
1775709a4b5SWarner Losh 		}
17866c61390SWarner Losh 	}
1795709a4b5SWarner Losh 	if (optlen == 0)
1805709a4b5SWarner Losh 		return;
18166c61390SWarner Losh 	printf("Option:\n");
1825709a4b5SWarner Losh 	if (Aflag)
1835709a4b5SWarner Losh 		asciidump(opt, optlen);
1845709a4b5SWarner Losh 	else if (bflag)
1855709a4b5SWarner Losh 		bindump(opt, optlen);
1865709a4b5SWarner Losh 	else if (uflag)
1875709a4b5SWarner Losh 		utf8dump(opt, optlen);
1885709a4b5SWarner Losh 	else
1895709a4b5SWarner Losh 		hexdump(opt, optlen);
1905709a4b5SWarner Losh }
191