Blame SOURCES/0037-Implement-efivar-export-foo.var.patch

d5c737
From 488976e782a7307cc2df4e1a8aaea1f6dfa757dd Mon Sep 17 00:00:00 2001
d5c737
From: Peter Jones <pjones@redhat.com>
d5c737
Date: Mon, 17 Jun 2019 15:04:11 -0400
d5c737
Subject: [PATCH 37/63] Implement 'efivar --export=foo.var'
d5c737
d5c737
Signed-off-by: Peter Jones <pjones@redhat.com>
d5c737
---
d5c737
 .gitignore                  |  17 +-
d5c737
 src/Makefile                |   2 +-
d5c737
 src/crc32.h                 |  19 ++
d5c737
 src/efivar.c                | 362 ++++++++++++++++++++------
d5c737
 src/export.c                | 502 +++++++++++++++++++++++++++++++++---
d5c737
 src/gpt.c                   |  18 --
d5c737
 src/include/efivar/efivar.h |   3 +
d5c737
 7 files changed, 783 insertions(+), 140 deletions(-)
d5c737
d5c737
diff --git a/.gitignore b/.gitignore
d5c737
index 5c3fd0e3f52..947d88eec42 100644
d5c737
--- a/.gitignore
d5c737
+++ b/.gitignore
d5c737
@@ -1,23 +1,26 @@
d5c737
+.*.c.P
d5c737
+.*.h.P
d5c737
+.*.d
d5c737
 .*.sw?
d5c737
 *~
d5c737
 *.a
d5c737
+*.env
d5c737
 *.E
d5c737
 *.o
d5c737
+*.map
d5c737
 *.pc
d5c737
 *.S
d5c737
 !src/guids.S
d5c737
 *.so
d5c737
 *.so.*
d5c737
+*.spec
d5c737
 *.tar.*
d5c737
-.*.c.P
d5c737
-.*.h.P
d5c737
-.*.d
d5c737
+*.var
d5c737
 core.*
d5c737
-*.spec
d5c737
+cov-int
d5c737
+vgcore.*
d5c737
+scan-results/
d5c737
 src/efivar
d5c737
 src/efivar-static
d5c737
 src/makeguids
d5c737
 src/guid-symbols.c
d5c737
-*.map
d5c737
-cov-int
d5c737
-scan-results/
d5c737
diff --git a/src/Makefile b/src/Makefile
d5c737
index ecbbc02e1f7..addfaa03c85 100644
d5c737
--- a/src/Makefile
d5c737
+++ b/src/Makefile
d5c737
@@ -17,7 +17,7 @@ STATICTARGETS=$(STATICLIBTARGETS) $(STATICBINTARGETS)
d5c737
 LIBEFIBOOT_SOURCES = crc32.c creator.c disk.c gpt.c loadopt.c path-helpers.c \
d5c737
 		     linux.c $(wildcard linux-*.c)
d5c737
 LIBEFIBOOT_OBJECTS = $(patsubst %.c,%.o,$(LIBEFIBOOT_SOURCES))
d5c737
-LIBEFIVAR_SOURCES = dp.c dp-acpi.c dp-hw.c dp-media.c dp-message.c \
d5c737
+LIBEFIVAR_SOURCES = crc32.c dp.c dp-acpi.c dp-hw.c dp-media.c dp-message.c \
d5c737
 	efivarfs.c error.c export.c guid.c guids.S guid-symbols.c \
d5c737
 	lib.c vars.c
d5c737
 LIBEFIVAR_OBJECTS = $(patsubst %.S,%.o,$(patsubst %.c,%.o,$(LIBEFIVAR_SOURCES)))
d5c737
diff --git a/src/crc32.h b/src/crc32.h
d5c737
index b5b975a5768..4e833aafac0 100644
d5c737
--- a/src/crc32.h
d5c737
+++ b/src/crc32.h
d5c737
@@ -29,6 +29,25 @@
d5c737
 
d5c737
 extern uint32_t crc32 (const void *buf, unsigned long len, uint32_t seed);
d5c737
 
d5c737
+/**
d5c737
+ * efi_crc32() - EFI version of crc32 function
d5c737
+ * @buf: buffer to calculate crc32 of
d5c737
+ * @len - length of buf
d5c737
+ *
d5c737
+ * Description: Returns EFI-style CRC32 value for @buf
d5c737
+ *
d5c737
+ * This function uses the little endian Ethernet polynomial
d5c737
+ * but seeds the function with ~0, and xor's with ~0 at the end.
d5c737
+ * Note, the EFI Specification, v1.02, has a reference to
d5c737
+ * Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
d5c737
+ */
d5c737
+static inline uint32_t
d5c737
+efi_crc32(const void *buf, unsigned long len)
d5c737
+{
d5c737
+	return (crc32(buf, len, ~0L) ^ ~0L);
d5c737
+}
d5c737
+
d5c737
+
d5c737
 #endif /* _CRC32_H */
d5c737
 
d5c737
 // vim:fenc=utf-8:tw=75:noet
d5c737
diff --git a/src/efivar.c b/src/efivar.c
d5c737
index 7f16ab15bab..885a9af864b 100644
d5c737
--- a/src/efivar.c
d5c737
+++ b/src/efivar.c
d5c737
@@ -46,6 +46,8 @@ extern int optind, opterr, optopt;
d5c737
 #define ACTION_LIST_GUIDS	0x08
d5c737
 #define ACTION_WRITE		0x10
d5c737
 #define ACTION_PRINT_DEC	0x20
d5c737
+#define ACTION_IMPORT		0x40
d5c737
+#define ACTION_EXPORT		0x80
d5c737
 
d5c737
 #define EDIT_APPEND	0
d5c737
 #define EDIT_WRITE	1
d5c737
@@ -173,31 +175,10 @@ bad_name:
d5c737
 }
d5c737
 
d5c737
 static void
d5c737
-show_variable(char *guid_name, int display_type)
d5c737
+show_variable_data(efi_guid_t guid, const char *name, uint32_t attributes,
d5c737
+		   uint8_t *data, size_t data_size,
d5c737
+		   int display_type)
d5c737
 {
d5c737
-	efi_guid_t guid = efi_guid_empty;
d5c737
-	char *name = NULL;
d5c737
-	int rc;
d5c737
-
d5c737
-	uint8_t *data = NULL;
d5c737
-	size_t data_size = 0;
d5c737
-	uint32_t attributes;
d5c737
-
d5c737
-	parse_name(guid_name, &name, &guid);
d5c737
-	if (!name || efi_guid_is_empty(&guid)) {
d5c737
-		fprintf(stderr, "efivar: could not parse variable name.\n");
d5c737
-		show_errors();
d5c737
-		exit(1);
d5c737
-	}
d5c737
-
d5c737
-	errno = 0;
d5c737
-	rc = efi_get_variable(guid, name, &data, &data_size, &attributes);
d5c737
-	if (rc < 0) {
d5c737
-		fprintf(stderr, "efivar: show variable: %m\n");
d5c737
-		show_errors();
d5c737
-		exit(1);
d5c737
-	}
d5c737
-
d5c737
 	if (display_type == SHOW_VERBOSE) {
d5c737
 		printf("GUID: "GUID_FORMAT "\n",
d5c737
 		       guid.a, guid.b, guid.c, bswap_16(guid.d),
d5c737
@@ -257,6 +238,117 @@ show_variable(char *guid_name, int display_type)
d5c737
 		}
d5c737
 		printf("\n");
d5c737
 	}
d5c737
+}
d5c737
+
d5c737
+static void
d5c737
+show_variable(char *guid_name, int display_type)
d5c737
+{
d5c737
+	efi_guid_t guid = efi_guid_empty;
d5c737
+	char *name = NULL;
d5c737
+	int rc;
d5c737
+
d5c737
+	uint8_t *data = NULL;
d5c737
+	size_t data_size = 0;
d5c737
+	uint32_t attributes;
d5c737
+
d5c737
+	parse_name(guid_name, &name, &guid);
d5c737
+	if (!name || efi_guid_is_empty(&guid)) {
d5c737
+		fprintf(stderr, "efivar: could not parse variable name.\n");
d5c737
+		show_errors();
d5c737
+		exit(1);
d5c737
+	}
d5c737
+
d5c737
+	errno = 0;
d5c737
+	rc = efi_get_variable(guid, name, &data, &data_size, &attributes);
d5c737
+	if (rc < 0) {
d5c737
+		fprintf(stderr, "efivar: show variable: %m\n");
d5c737
+		show_errors();
d5c737
+		exit(1);
d5c737
+	}
d5c737
+
d5c737
+	show_variable_data(guid, name, attributes,
d5c737
+			   data, data_size, display_type);
d5c737
+
d5c737
+	free(name);
d5c737
+	if (data)
d5c737
+		free(data);
d5c737
+}
d5c737
+
d5c737
+static void
d5c737
+save_variable_data(efi_variable_t *var, char *outfile, bool dmpstore)
d5c737
+{
d5c737
+	FILE *out = NULL;
d5c737
+	ssize_t sz;
d5c737
+	uint8_t *data = NULL;
d5c737
+	size_t datasz = 0;
d5c737
+	ssize_t (*export)(efi_variable_t *var, uint8_t *data, size_t size) =
d5c737
+		dmpstore ? efi_variable_export_dmpstore : efi_variable_export;
d5c737
+
d5c737
+	out = fopen(outfile, "w");
d5c737
+	if (!out)
d5c737
+		err(1, "Could not open \"%s\" for writing", outfile);
d5c737
+
d5c737
+	sz = export(var, data, datasz);
d5c737
+	data = calloc(sz, 1);
d5c737
+	if (!data)
d5c737
+		err(1, "Could not allocate memory");
d5c737
+	datasz = sz;
d5c737
+
d5c737
+	sz = export(var, data, datasz);
d5c737
+	if (sz < 0)
d5c737
+		err(1, "Could not format data");
d5c737
+	datasz = sz;
d5c737
+
d5c737
+	sz = fwrite(data, 1, datasz, out);
d5c737
+	if (sz < (ssize_t)datasz)
d5c737
+		err(1, "Could not write to \"%s\"", outfile);
d5c737
+
d5c737
+	fflush(out);
d5c737
+	fclose(out);
d5c737
+}
d5c737
+
d5c737
+static void
d5c737
+save_variable(char *guid_name, char *outfile, bool dmpstore)
d5c737
+{
d5c737
+	efi_guid_t guid = efi_guid_empty;
d5c737
+	char *name = NULL;
d5c737
+	int rc;
d5c737
+
d5c737
+	uint8_t *data = NULL;
d5c737
+	size_t data_size = 0;
d5c737
+	uint32_t attributes = 7;
d5c737
+	efi_variable_t *var;
d5c737
+
d5c737
+	parse_name(guid_name, &name, &guid);
d5c737
+	if (!name || efi_guid_is_empty(&guid)) {
d5c737
+		fprintf(stderr, "efivar: could not parse variable name.\n");
d5c737
+		show_errors();
d5c737
+		exit(1);
d5c737
+	}
d5c737
+
d5c737
+	errno = 0;
d5c737
+	rc = efi_get_variable(guid, name, &data, &data_size, &attributes);
d5c737
+	if (rc < 0) {
d5c737
+		fprintf(stderr, "efivar: show variable: %m\n");
d5c737
+		show_errors();
d5c737
+		exit(1);
d5c737
+	}
d5c737
+
d5c737
+	var = efi_variable_alloc();
d5c737
+	if (!var) {
d5c737
+		fprintf(stderr, "efivar: could not allocate variable storage.\n");
d5c737
+		show_errors();
d5c737
+		exit(1);
d5c737
+	}
d5c737
+
d5c737
+	efi_variable_set_name(var, (unsigned char *)name);
d5c737
+	efi_variable_set_guid(var, &guid);
d5c737
+	efi_variable_set_attributes(var, attributes);
d5c737
+	efi_variable_set_data(var, data, data_size);
d5c737
+
d5c737
+	save_variable_data(var, outfile, dmpstore);
d5c737
+
d5c737
+	efi_variable_free(var, false);
d5c737
 
d5c737
 	free(name);
d5c737
 	if (data)
d5c737
@@ -372,16 +464,18 @@ usage(int ret)
d5c737
 	FILE *out = ret == 0 ? stdout : stderr;
d5c737
 	fprintf(out,
d5c737
 		"Usage: %s [OPTION...]\n"
d5c737
+		"  -t, --attributes=<attributes>     attributes to use on append\n"
d5c737
 		"  -l, --list                        list current variables\n"
d5c737
 		"  -p, --print                       print variable specified by --name\n"
d5c737
+		"  -D, --dmpstore                    use DMPSTORE format when exporting\n"
d5c737
 		"  -d, --print-decimal               print variable in decimal values specified\n"
d5c737
 		"                                    by --name\n"
d5c737
 		"  -n, --name=<guid-name>            variable to manipulate, in the form\n"
d5c737
 		"                                    8be4df61-93ca-11d2-aa0d-00e098032b8c-Boot0000\n"
d5c737
 		"  -a, --append                      append to variable specified by --name\n"
d5c737
+		"  -f, --datafile=<file>             load or save variable contents from <file>\n"
d5c737
 		"  -e, --export=<file>               export variable to <file>\n"
d5c737
-		"  -f, --fromfile=<file>             use data from <file>\n"
d5c737
-		"  -t, --attributes=<attributes>     attributes to use on append\n"
d5c737
+		"  -i, --import=<file>               import variable from 
d5c737
 		"  -L, --list-guids                  show internal guid list\n"
d5c737
 		"  -w, --write                       write to variable specified by --name\n\n"
d5c737
 		"Help options:\n"
d5c737
@@ -398,55 +492,79 @@ int main(int argc, char *argv[])
d5c737
 	int action = 0;
d5c737
 	uint8_t *data = NULL;
d5c737
 	size_t data_size = 0;
d5c737
-	char *name = NULL;
d5c737
-	char *file = NULL;
d5c737
-	uint32_t attributes = 0;
d5c737
-	char *sopts = "lpdn:af:t:Lw?";
d5c737
-	struct option lopts[] =
d5c737
-		{ {"list", no_argument, 0, 'l'},
d5c737
-		  {"print", no_argument, 0, 'p'},
d5c737
-		  {"print-decimal", no_argument, 0, 'd'},
d5c737
-		  {"name", required_argument, 0, 'n'},
d5c737
-		  {"append", no_argument, 0, 'a'},
d5c737
-		  {"fromfile", required_argument, 0, 'f'},
d5c737
-		  {"attributes", required_argument, 0, 't'},
d5c737
-		  {"list-guids", no_argument, 0, 'L'},
d5c737
-		  {"write", no_argument, 0, 'w'},
d5c737
-		  {"help", no_argument, 0, '?'},
d5c737
-		  {"usage", no_argument, 0, 0},
d5c737
-		  {0, 0, 0, 0}
d5c737
-		};
d5c737
+	char *guid_name = NULL;
d5c737
+	char *infile = NULL;
d5c737
+	char *outfile = NULL;
d5c737
+	char *datafile = NULL;
d5c737
+	bool dmpstore = false;
d5c737
+	int verbose = 0;
d5c737
+	uint32_t attributes = EFI_VARIABLE_NON_VOLATILE
d5c737
+			      | EFI_VARIABLE_BOOTSERVICE_ACCESS
d5c737
+			      | EFI_VARIABLE_RUNTIME_ACCESS;
d5c737
+	char *sopts = "aA:Dde:f:i:Llpn:vw?";
d5c737
+	struct option lopts[] = {
d5c737
+		{"append", no_argument, 0, 'a'},
d5c737
+		{"attributes", required_argument, 0, 'A'},
d5c737
+		{"datafile", required_argument, 0, 'f'},
d5c737
+		{"dmpstore", no_argument, 0, 'D'},
d5c737
+		{"export", required_argument, 0, 'e'},
d5c737
+		{"help", no_argument, 0, '?'},
d5c737
+		{"import", required_argument, 0, 'i'},
d5c737
+		{"list", no_argument, 0, 'l'},
d5c737
+		{"list-guids", no_argument, 0, 'L'},
d5c737
+		{"name", required_argument, 0, 'n'},
d5c737
+		{"print", no_argument, 0, 'p'},
d5c737
+		{"print-decimal", no_argument, 0, 'd'},
d5c737
+		{"usage", no_argument, 0, 0},
d5c737
+		{"verbose", no_argument, 0, 'v'},
d5c737
+		{"write", no_argument, 0, 'w'},
d5c737
+		{0, 0, 0, 0}
d5c737
+	};
d5c737
 
d5c737
 	while ((c = getopt_long(argc, argv, sopts, lopts, &i)) != -1) {
d5c737
 		switch (c) {
d5c737
-			case 'l':
d5c737
-				action |= ACTION_LIST;
d5c737
+			case 'A':
d5c737
+				attributes = strtoul(optarg, NULL, 10);
d5c737
+				if (errno == ERANGE || errno == EINVAL)
d5c737
+					err(1,
d5c737
+					    "invalid argument for -t: %s: %m\n",
d5c737
+					    optarg);
d5c737
 				break;
d5c737
-			case 'p':
d5c737
-				action |= ACTION_PRINT;
d5c737
+			case 'a':
d5c737
+				action |= ACTION_APPEND;
d5c737
+				break;
d5c737
+			case 'D':
d5c737
+				dmpstore = true;
d5c737
 				break;
d5c737
 			case 'd':
d5c737
 				action |= ACTION_PRINT_DEC;
d5c737
 				break;
d5c737
-			case 'n':
d5c737
-				name = optarg;
d5c737
-				break;
d5c737
-			case 'a':
d5c737
-				action |= ACTION_APPEND;
d5c737
+			case 'e':
d5c737
+				action |= ACTION_EXPORT;
d5c737
+				outfile = optarg;
d5c737
 				break;
d5c737
 			case 'f':
d5c737
-				file = optarg;
d5c737
+				datafile = optarg;
d5c737
 				break;
d5c737
-			case 't':
d5c737
-				attributes = strtoul(optarg, NULL, 10);
d5c737
-				if (errno == ERANGE || errno == EINVAL)
d5c737
-					err(1,
d5c737
-					    "invalid argument for -t: %s: %m\n",
d5c737
-					    optarg);
d5c737
+			case 'i':
d5c737
+				action |= ACTION_IMPORT;
d5c737
+				infile = optarg;
d5c737
 				break;
d5c737
 			case 'L':
d5c737
 				action |= ACTION_LIST_GUIDS;
d5c737
 				break;
d5c737
+			case 'l':
d5c737
+				action |= ACTION_LIST;
d5c737
+				break;
d5c737
+			case 'n':
d5c737
+				guid_name = optarg;
d5c737
+				break;
d5c737
+			case 'p':
d5c737
+				action |= ACTION_PRINT;
d5c737
+				break;
d5c737
+			case 'v':
d5c737
+				verbose += 1;
d5c737
+				break;
d5c737
 			case 'w':
d5c737
 				action |= ACTION_WRITE;
d5c737
 				break;
d5c737
@@ -460,7 +578,9 @@ int main(int argc, char *argv[])
d5c737
 		}
d5c737
 	}
d5c737
 
d5c737
-	if (name)
d5c737
+	efi_set_verbose(verbose, stderr);
d5c737
+
d5c737
+	if (guid_name && !outfile)
d5c737
 		action |= ACTION_PRINT;
d5c737
 
d5c737
 	switch (action) {
d5c737
@@ -468,23 +588,23 @@ int main(int argc, char *argv[])
d5c737
 			list_all_variables();
d5c737
 			break;
d5c737
 		case ACTION_PRINT:
d5c737
-			validate_name(name);
d5c737
-			show_variable(name, SHOW_VERBOSE);
d5c737
+			validate_name(guid_name);
d5c737
+			show_variable(guid_name, SHOW_VERBOSE);
d5c737
 			break;
d5c737
 		case ACTION_PRINT_DEC | ACTION_PRINT:
d5c737
-			validate_name(name);
d5c737
-			show_variable(name, SHOW_DECIMAL);
d5c737
+			validate_name(guid_name);
d5c737
+			show_variable(guid_name, SHOW_DECIMAL);
d5c737
 			break;
d5c737
 		case ACTION_APPEND | ACTION_PRINT:
d5c737
-			validate_name(name);
d5c737
-			prepare_data(file, &data, &data_size);
d5c737
-			edit_variable(name, data, data_size, attributes,
d5c737
+			validate_name(guid_name);
d5c737
+			prepare_data(infile, &data, &data_size);
d5c737
+			edit_variable(guid_name, data, data_size, attributes,
d5c737
 				      EDIT_APPEND);
d5c737
 			break;
d5c737
 		case ACTION_WRITE | ACTION_PRINT:
d5c737
-			validate_name(name);
d5c737
-			prepare_data(file, &data, &data_size);
d5c737
-			edit_variable(name, data, data_size, attributes,
d5c737
+			validate_name(guid_name);
d5c737
+			prepare_data(infile, &data, &data_size);
d5c737
+			edit_variable(guid_name, data, data_size, attributes,
d5c737
 				      EDIT_WRITE);
d5c737
 			break;
d5c737
 		case ACTION_LIST_GUIDS: {
d5c737
@@ -509,10 +629,108 @@ int main(int argc, char *argv[])
d5c737
 					guid[i].symbol + strlen("efi_guid_"),
d5c737
 					guid[i].symbol, guid[i].name);
d5c737
 			}
d5c737
+			break;
d5c737
+					}
d5c737
+		case ACTION_EXPORT:
d5c737
+			if (datafile) {
d5c737
+				char *name = NULL;
d5c737
+				efi_guid_t guid = efi_guid_zero;
d5c737
+				efi_variable_t *var;
d5c737
+
d5c737
+				parse_name(guid_name, &name, &guid);
d5c737
+				prepare_data(datafile, &data, &data_size);
d5c737
+
d5c737
+				var = efi_variable_alloc();
d5c737
+				if (!var)
d5c737
+					err(1, "Could not allocate memory");
d5c737
+
d5c737
+				efi_variable_set_name(var, (unsigned char *)name);
d5c737
+				efi_variable_set_guid(var, &guid);
d5c737
+				efi_variable_set_attributes(var, attributes);
d5c737
+				efi_variable_set_data(var, data, data_size);
d5c737
+
d5c737
+				save_variable_data(var, outfile, dmpstore);
d5c737
+
d5c737
+				efi_variable_free(var, false);
d5c737
+			} else {
d5c737
+				validate_name(guid_name);
d5c737
+				save_variable(guid_name, outfile, dmpstore);
d5c737
+			}
d5c737
+			break;
d5c737
+		case ACTION_IMPORT:
d5c737
+		case ACTION_IMPORT | ACTION_PRINT:
d5c737
+		case ACTION_IMPORT | ACTION_PRINT | ACTION_PRINT_DEC:
d5c737
+			{
d5c737
+				ssize_t sz;
d5c737
+				efi_variable_t *var = NULL;
d5c737
+				char *name;
d5c737
+				efi_guid_t *guid;
d5c737
+				uint64_t attributes;
d5c737
+				int display_type = (action & ACTION_PRINT_DEC)
d5c737
+					? SHOW_VERBOSE|SHOW_DECIMAL
d5c737
+					: SHOW_VERBOSE;
d5c737
+
d5c737
+
d5c737
+				prepare_data(infile, &data, &data_size);
d5c737
+				sz = efi_variable_import(data, data_size, &var);
d5c737
+				if (sz < 0)
d5c737
+					err(1, "Could not import data from \"%s\"", infile);
d5c737
+
d5c737
+				free(data);
d5c737
+				data = NULL;
d5c737
+				data_size = 0;
d5c737
+
d5c737
+				name = (char *)efi_variable_get_name(var);
d5c737
+				efi_variable_get_guid(var, &guid);
d5c737
+				efi_variable_get_attributes(var, &attributes);
d5c737
+				efi_variable_get_data(var, &data, &data_size);
d5c737
+
d5c737
+				if (datafile) {
d5c737
+					FILE *out;
d5c737
+					int rc;
d5c737
+
d5c737
+					out = fopen(datafile, "w");
d5c737
+					if (!out)
d5c737
+						err(1, "Could not open \"%s\" for writing",
d5c737
+						    datafile);
d5c737
+
d5c737
+					rc = fwrite(data, data_size, 1, out);
d5c737
+					if (rc < (long)data_size)
d5c737
+						err(1, "Could not write to \"%s\"",
d5c737
+						    datafile);
d5c737
+
d5c737
+					fclose(out);
d5c737
+					free(guid_name);
d5c737
+				}
d5c737
+				if (action & ACTION_PRINT)
d5c737
+					show_variable_data(*guid, name,
d5c737
+						((uint32_t)(attributes & 0xffffffff)),
d5c737
+						 data, data_size, display_type);
d5c737
+
d5c737
+				efi_variable_free(var, false);
d5c737
+				break;
d5c737
+			}
d5c737
+		case ACTION_IMPORT | ACTION_EXPORT:
d5c737
+			{
d5c737
+				efi_variable_t *var = NULL;
d5c737
+				ssize_t sz;
d5c737
+
d5c737
+				if (datafile)
d5c737
+					errx(1, "--datafile cannot be used with --import and --export");
d5c737
+
d5c737
+				prepare_data(infile, &data, &data_size);
d5c737
+				sz = efi_variable_import(data, data_size, &var);
d5c737
+				if (sz < 0)
d5c737
+					err(1, "Could not import data from \"%s\"", infile);
d5c737
+
d5c737
+				save_variable_data(var, outfile, dmpstore);
d5c737
+
d5c737
+				efi_variable_free(var, false);
d5c737
+				break;
d5c737
+			}
d5c737
 		case ACTION_USAGE:
d5c737
 		default:
d5c737
 			usage(EXIT_FAILURE);
d5c737
-		}
d5c737
 	};
d5c737
 
d5c737
 	return 0;
d5c737
diff --git a/src/export.c b/src/export.c
d5c737
index 6b78412cce1..cfb021525ff 100644
d5c737
--- a/src/export.c
d5c737
+++ b/src/export.c
d5c737
@@ -27,7 +27,7 @@
d5c737
 
d5c737
 #include "efivar.h"
d5c737
 
d5c737
-#define EFIVAR_MAGIC 0xf3df1597
d5c737
+#define EFIVAR_MAGIC 0xf3df1597u
d5c737
 
d5c737
 #define ATTRS_UNSET 0xa5a5a5a5a5a5a5a5
d5c737
 #define ATTRS_MASK 0xffffffff
d5c737
@@ -50,12 +50,166 @@ struct efi_variable {
d5c737
  *	uint32_t data_len;
d5c737
  *	char16_t name[];
d5c737
  *	uint8_t data[];
d5c737
- *	uint32_t magic;
d5c737
+ *	uint32_t crc32;
d5c737
+ * }
d5c737
+ *
d5c737
+ * Unfortunately the exported structure from dmpstore is:
d5c737
+ * struct {
d5c737
+ *	uint32_t name_size; // in bytes
d5c737
+ *	uint32_t data_size; // in bytes
d5c737
+ *	char16_t name[];
d5c737
+ *	efi_guid_t guid;
d5c737
+ *	uint32_t attr;
d5c737
+ *	unit8_t data[];
d5c737
+ *	uint32_t crc32;
d5c737
  * }
d5c737
  */
d5c737
 
d5c737
-ssize_t NONNULL(1, 3) PUBLIC
d5c737
-efi_variable_import(uint8_t *data, size_t size, efi_variable_t **var_out)
d5c737
+#ifdef EFIVAR_BUILD_ENVIRONMENT
d5c737
+#error wtf
d5c737
+#endif
d5c737
+
d5c737
+ssize_t NONNULL(1, 3)
d5c737
+efi_variable_import_dmpstore(uint8_t *data, size_t size,
d5c737
+			     efi_variable_t **var_out)
d5c737
+{
d5c737
+	efi_variable_t var;
d5c737
+	uint32_t namesz;
d5c737
+	uint32_t datasz;
d5c737
+	size_t min = sizeof (uint32_t)		/* name size */
d5c737
+		   + sizeof (uint32_t)		/* data size */
d5c737
+		   + sizeof (char16_t)		/* two bytes of name */
d5c737
+		   + sizeof (efi_guid_t)	/* guid */
d5c737
+		   + sizeof (uint32_t)		/* attr */
d5c737
+		   + 1				/* one byte of data */
d5c737
+		   + sizeof (uint32_t);		/* crc32 */
d5c737
+	size_t sz = sizeof (uint32_t)		/* name size */
d5c737
+		  + sizeof (uint32_t)		/* data size */
d5c737
+		  + sizeof (efi_guid_t)		/* guid */
d5c737
+		  + sizeof (uint32_t)		/* attr */
d5c737
+		  + sizeof (uint32_t);		/* crc32 */
d5c737
+	uint8_t *ptr = data;
d5c737
+	uint32_t crc;
d5c737
+	int saved_errno;
d5c737
+
d5c737
+	if (size <= min) {
d5c737
+etoosmall:
d5c737
+		errno = EINVAL;
d5c737
+		efi_error("data size is too small for dmpstore variable (%zu < %zu)",
d5c737
+			  size, min);
d5c737
+		return -1;
d5c737
+	}
d5c737
+
d5c737
+	memset(&var, 0, sizeof(var));
d5c737
+
d5c737
+	namesz = *(uint32_t *)ptr;
d5c737
+	debug("namesz:%"PRIu32, namesz);
d5c737
+	ptr += sizeof(uint32_t);
d5c737
+
d5c737
+	if (namesz <= 2) {
d5c737
+		errno = EINVAL;
d5c737
+		debug("name size (%"PRIu32") must be greater than 2", namesz);
d5c737
+		return -1;
d5c737
+	}
d5c737
+
d5c737
+	if (namesz % 2 != 0) {
d5c737
+		errno = EINVAL;
d5c737
+		efi_error("name size (%"PRIu32") cannot be odd", namesz);
d5c737
+		return -1;
d5c737
+	}
d5c737
+
d5c737
+	datasz = *(uint32_t *)ptr;
d5c737
+	ptr += sizeof(uint32_t);
d5c737
+	debug("datasz:%"PRIu32, datasz);
d5c737
+
d5c737
+	if (datasz == 0) {
d5c737
+		errno = EINVAL;
d5c737
+		efi_error("data size (%"PRIu32") must be nonzero", datasz);
d5c737
+		return -1;
d5c737
+	}
d5c737
+
d5c737
+	if (add(sz, namesz, &sz)) {
d5c737
+overflow:
d5c737
+		errno = EOVERFLOW;
d5c737
+		efi_error("arithmetic overflow computing allocation size");
d5c737
+		return -1;
d5c737
+	}
d5c737
+
d5c737
+	if (add(sz, datasz, &min))
d5c737
+		goto overflow;
d5c737
+
d5c737
+	if (size < min)
d5c737
+		goto etoosmall;
d5c737
+	size = min;
d5c737
+
d5c737
+	if (!(ptr[namesz - 1] == 0 && ptr[namesz -2] == 0)) {
d5c737
+		errno = EINVAL;
d5c737
+		efi_error("variable name is not properly terminated.");
d5c737
+		return -1;
d5c737
+	}
d5c737
+
d5c737
+	crc = efi_crc32(data, size - sizeof(uint32_t));
d5c737
+	debug("efi_crc32(%p, %lu) -> 0x%"PRIx32", expected 0x%"PRIx32,
d5c737
+	      data, size - sizeof(uint32_t), crc,
d5c737
+	      *(uint32_t*)(data + size - sizeof(uint32_t)));
d5c737
+
d5c737
+	if (memcmp(data + size - sizeof(uint32_t),
d5c737
+		    &crc, sizeof(uint32_t))) {
d5c737
+		errno = EINVAL;
d5c737
+		efi_error("crc32 did not match");
d5c737
+		return -1;
d5c737
+	}
d5c737
+
d5c737
+	var.name = ucs2_to_utf8(ptr, -1);
d5c737
+	if (!var.name)
d5c737
+		goto oom;
d5c737
+	ptr += namesz;
d5c737
+
d5c737
+	var.guid = malloc(sizeof (efi_guid_t));
d5c737
+	if (!var.guid)
d5c737
+		goto oom;
d5c737
+	memcpy(var.guid, ptr, sizeof (efi_guid_t));
d5c737
+	ptr += sizeof (efi_guid_t);
d5c737
+
d5c737
+	var.attrs = *(uint32_t *)ptr;
d5c737
+	ptr += sizeof(uint32_t);
d5c737
+
d5c737
+	var.data_size = datasz;
d5c737
+	var.data = malloc(datasz);
d5c737
+	if (!var.data) {
d5c737
+		efi_error("Could not allocate %"PRIu32" bytes", datasz);
d5c737
+		goto oom;
d5c737
+	}
d5c737
+	memcpy(var.data, ptr, datasz);
d5c737
+
d5c737
+	if (!*var_out) {
d5c737
+		*var_out =malloc(sizeof (var));
d5c737
+		if (!*var_out)
d5c737
+			goto oom;
d5c737
+		memcpy(*var_out, &var, sizeof (var));
d5c737
+	} else {
d5c737
+		return -1;
d5c737
+	}
d5c737
+	return size;
d5c737
+oom:
d5c737
+	saved_errno = errno;
d5c737
+
d5c737
+	if (var.guid)
d5c737
+		free(var.guid);
d5c737
+
d5c737
+	if (var.name)
d5c737
+		free(var.name);
d5c737
+
d5c737
+	if (var.data)
d5c737
+		free(var.data);
d5c737
+
d5c737
+	errno = saved_errno;
d5c737
+	efi_error("Could not allocate memory");
d5c737
+	return -1;
d5c737
+}
d5c737
+
d5c737
+ssize_t NONNULL(1, 3)
d5c737
+efi_variable_import_efivar(uint8_t *data, size_t datasz, efi_variable_t **var_out)
d5c737
 {
d5c737
 	efi_variable_t var;
d5c737
 	size_t min = sizeof (uint32_t) * 2	/* magic */
d5c737
@@ -63,47 +217,83 @@ efi_variable_import(uint8_t *data, size_t size, efi_variable_t **var_out)
d5c737
 		   + sizeof (uint64_t)		/* attr */
d5c737
 		   + sizeof (efi_guid_t)	/* guid */
d5c737
 		   + sizeof (uint32_t) * 2	/* name_len and data_len */
d5c737
-		   + sizeof (char16_t)	/* two bytes of name */
d5c737
-		   + 1;				/* one byte of data */
d5c737
+		   + sizeof (char16_t)		/* two bytes of name */
d5c737
+		   + 1				/* one byte of data */
d5c737
+		   + 4;				/* crc32 */
d5c737
+	uint32_t crc;
d5c737
+	uint8_t *ptr = data;
d5c737
+	uint32_t magic = EFIVAR_MAGIC;
d5c737
+	int test;
d5c737
+
d5c737
 	errno = EINVAL;
d5c737
-	if (size <= min)
d5c737
+	if (datasz <= min)
d5c737
 		return -1;
d5c737
 
d5c737
-	uint8_t *ptr = data;
d5c737
-	uint32_t magic = EFIVAR_MAGIC;
d5c737
-	if (memcmp(data, &magic, sizeof (uint32_t)) ||
d5c737
-			memcmp(data + size - sizeof (uint32_t), &magic,
d5c737
-				sizeof (uint32_t)))
d5c737
+	test = memcmp(data, &magic, sizeof (uint32_t));
d5c737
+	debug("test magic 0: cmp(0x%04x,0x%04x)->%d", *(uint32_t *)data, magic, test);
d5c737
+	if (test) {
d5c737
+		errno = EINVAL;
d5c737
+		efi_error("MAGIC for file format did not match.");
d5c737
 		return -1;
d5c737
-	size -= sizeof (uint32_t);
d5c737
+	}
d5c737
+
d5c737
 	ptr += sizeof (uint32_t);
d5c737
 
d5c737
+	debug("test version");
d5c737
 	if (*(uint32_t *)ptr == 1) {
d5c737
 		ptr += sizeof (uint32_t);
d5c737
+		debug("version 1");
d5c737
+
d5c737
 		var.attrs = *(uint64_t *)ptr;
d5c737
-		ptr += sizeof (uint32_t);
d5c737
+		ptr += sizeof (uint64_t);
d5c737
+		debug("var.attrs:0x%08"PRIx64, var.attrs);
d5c737
 
d5c737
 		var.guid = malloc(sizeof (efi_guid_t));
d5c737
 		if (!var.guid)
d5c737
 			return -1;
d5c737
 		*var.guid = *(efi_guid_t *)ptr;
d5c737
 		ptr += sizeof (efi_guid_t);
d5c737
+		debug("var.guid:"GUID_FORMAT,
d5c737
+		      var.guid->a, var.guid->b, var.guid->c,
d5c737
+		      bswap_16(var.guid->d),
d5c737
+		      var.guid->e[0], var.guid->e[1], var.guid->e[2],
d5c737
+		      var.guid->e[3], var.guid->e[4], var.guid->e[5]);
d5c737
 
d5c737
 		uint32_t name_len = *(uint32_t *)ptr;
d5c737
 		ptr += sizeof (uint32_t);
d5c737
+		debug("name_len:%"PRIu32, name_len);
d5c737
+
d5c737
 		uint32_t data_len = *(uint32_t *)ptr;
d5c737
 		ptr += sizeof (uint32_t);
d5c737
+		debug("data_len:%"PRIu32, data_len);
d5c737
+
d5c737
+		min -= 3;
d5c737
+		min += name_len;
d5c737
+		min += data_len;
d5c737
 
d5c737
-		if (name_len < 1 ||
d5c737
-		    name_len != ((data + size) - ptr - data_len) ||
d5c737
+		if (name_len < 2 ||
d5c737
+		    name_len > (datasz - data_len) ||
d5c737
 		    data_len < 1 ||
d5c737
-		    data_len != ((data + size) - ptr - name_len)) {
d5c737
+		    data_len > (datasz - name_len)) {
d5c737
 			int saved_errno = errno;
d5c737
 			free(var.guid);
d5c737
 			errno = saved_errno;
d5c737
 			return -1;
d5c737
 		}
d5c737
 
d5c737
+		crc = efi_crc32(data, datasz - sizeof(uint32_t));
d5c737
+		debug("efi_crc32(%p, %lu) -> 0x%"PRIx32", expected 0x%"PRIx32,
d5c737
+		      data, datasz - sizeof(uint32_t), crc,
d5c737
+		      *(uint32_t*)(data + datasz - sizeof(uint32_t)));
d5c737
+
d5c737
+		if (memcmp(data + datasz - sizeof (uint32_t), &crc,
d5c737
+			   sizeof (uint32_t))) {
d5c737
+			free(var.guid);
d5c737
+			errno = EINVAL;
d5c737
+			efi_error("crc32 did not match");
d5c737
+			return -1;
d5c737
+		}
d5c737
+
d5c737
 		var.name = calloc(1, name_len + 1);
d5c737
 		if (!var.name) {
d5c737
 			int saved_errno = errno;
d5c737
@@ -115,7 +305,8 @@ efi_variable_import(uint8_t *data, size_t size, efi_variable_t **var_out)
d5c737
 		char16_t *wname = (char16_t *)ptr;
d5c737
 		for (uint32_t i = 0; i < name_len; i++)
d5c737
 			var.name[i] = wname[i] & 0xff;
d5c737
-		ptr += name_len * 2;
d5c737
+		ptr += name_len;
d5c737
+		debug("name:%s", var.name);
d5c737
 
d5c737
 		var.data_size = data_len;
d5c737
 		var.data = malloc(data_len);
d5c737
@@ -143,31 +334,228 @@ efi_variable_import(uint8_t *data, size_t size, efi_variable_t **var_out)
d5c737
 	} else {
d5c737
 		return -1;
d5c737
 	}
d5c737
-	return size;
d5c737
+	return min;
d5c737
+}
d5c737
+
d5c737
+ssize_t NONNULL(1, 3) PUBLIC
d5c737
+efi_variable_import(uint8_t *data, size_t size, efi_variable_t **var_out)
d5c737
+{
d5c737
+	ssize_t rc;
d5c737
+
d5c737
+	rc = efi_variable_import_efivar(data, size, var_out);
d5c737
+	if (rc >= 0)
d5c737
+		return rc;
d5c737
+
d5c737
+	rc = efi_variable_import_dmpstore(data, size, var_out);
d5c737
+	return rc;
d5c737
 }
d5c737
 
d5c737
 ssize_t NONNULL(1) PUBLIC
d5c737
-efi_variable_export(efi_variable_t *var, uint8_t *data, size_t size)
d5c737
+efi_variable_export_dmpstore(efi_variable_t *var, uint8_t *data, size_t datasz)
d5c737
 {
d5c737
-	size_t name_len = strlen((char *)var->name);
d5c737
-
d5c737
-	size_t needed = sizeof (uint32_t)		/* magic */
d5c737
-		      + sizeof (uint32_t)		/* version */
d5c737
-		      + sizeof (uint64_t)		/* attr */
d5c737
-		      + sizeof (efi_guid_t)		/* guid */
d5c737
-		      + sizeof (uint32_t)		/* name_len */
d5c737
-		      + sizeof (uint32_t)		/* data_len */
d5c737
-		      + sizeof (char16_t) * name_len	/* name */
d5c737
-		      + var->data_size			/* data */
d5c737
-		      + sizeof (uint32_t);		/* magic again */
d5c737
-
d5c737
-	if (!data || size == 0) {
d5c737
+	uint32_t tmpu32;
d5c737
+	ssize_t tmpssz;
d5c737
+	uint32_t namesz;
d5c737
+	uint32_t needed = sizeof (uint32_t)		/* name_size */
d5c737
+			+ sizeof (uint32_t)		/* data_size */
d5c737
+			+ 2				/* name */
d5c737
+			+ sizeof (efi_guid_t)		/* guid */
d5c737
+			+ sizeof (uint32_t)		/* attrs */
d5c737
+			+ 1				/* data */
d5c737
+			+ 4;				/* crc32 */
d5c737
+	uint8_t *ptr;
d5c737
+	uint32_t crc;
d5c737
+
d5c737
+	if (!var) {
d5c737
+		errno = EINVAL;
d5c737
+		efi_error("var cannot be NULL");
d5c737
+		return -1;
d5c737
+	}
d5c737
+	if (!var->name) {
d5c737
+		errno = EINVAL;
d5c737
+		efi_error("var->name cannot be NULL");
d5c737
+		return -1;
d5c737
+	}
d5c737
+	if (!var->data) {
d5c737
+		errno = EINVAL;
d5c737
+		efi_error("var->data cannot be NULL");
d5c737
+		return -1;
d5c737
+	}
d5c737
+
d5c737
+	debug("data: %p datasz: %zu", data, datasz);
d5c737
+
d5c737
+	namesz = utf8size(var->name, -1);
d5c737
+	debug("sizeof(uint16_t):%zd * namesz:%"PRIu32, sizeof(uint16_t), namesz);
d5c737
+	if (mul(sizeof (uint16_t), namesz, &namesz)) {
d5c737
+overflow:
d5c737
+		errno = EOVERFLOW;
d5c737
+		efi_error("arithmetic overflow computing name size");
d5c737
+		return -1;
d5c737
+	}
d5c737
+	debug("namesz -> %"PRIu32, namesz);
d5c737
+
d5c737
+	/*
d5c737
+	 * Remove our stand-ins for name size and data size before we add
d5c737
+	 * them back in.
d5c737
+	 */
d5c737
+	needed -= 3;
d5c737
+
d5c737
+	debug("needed:%"PRIu32" + namesz:%"PRIu32, needed, namesz);
d5c737
+	if (add(needed, namesz, &needed))
d5c737
+		goto overflow;
d5c737
+	debug("needed -> %"PRIu32, needed);
d5c737
+
d5c737
+	debug("needed:%"PRIu32" + var->data_size:%zd", needed, var->data_size);
d5c737
+	if (add(needed, var->data_size, &needed))
d5c737
+		goto overflow;
d5c737
+	debug("needed -> %"PRIu32, needed);
d5c737
+
d5c737
+	if (!data || datasz == 0) {
d5c737
+		debug("data: %p datasz: %zd -> returning needed size %"PRIu32,
d5c737
+		      data, datasz, needed);
d5c737
 		return needed;
d5c737
-	} else if (size < needed) {
d5c737
-		return needed - size;
d5c737
 	}
d5c737
 
d5c737
-	uint8_t *ptr = data;
d5c737
+	debug("datasz:%zu needed: %"PRIu32, datasz, needed);
d5c737
+	if (datasz < needed) {
d5c737
+		efi_error("needed: %"PRIu32" datasz: %zd -> returning needed datasz %zu",
d5c737
+			  needed, datasz, needed - datasz);
d5c737
+		return needed - datasz;
d5c737
+	}
d5c737
+
d5c737
+	ptr = data;
d5c737
+
d5c737
+	tmpssz = utf8_to_ucs2(ptr + 8, datasz - 8, true, var->name);
d5c737
+	if (tmpssz < 0) {
d5c737
+		efi_error("UTF-8 to UCS-2 conversion failed");
d5c737
+		return -1;
d5c737
+	}
d5c737
+	tmpu32 = tmpssz;
d5c737
+	tmpu32 *= sizeof(uint16_t);
d5c737
+
d5c737
+	debug("namesz:%"PRIu32" - tmpu32:%"PRIu32, namesz, tmpu32);
d5c737
+	if (sub(namesz, tmpu32, &tmpu32))
d5c737
+		goto overflow;
d5c737
+	debug("tmpu32 -> %"PRIu32, tmpu32);
d5c737
+
d5c737
+	debug("namesz:%"PRIu32" - tmpu32:%"PRIu32, namesz, tmpu32);
d5c737
+	if (sub(namesz, tmpu32, &namesz))
d5c737
+		goto overflow;
d5c737
+	debug("namesz -> %"PRIu32, namesz);
d5c737
+
d5c737
+	debug("needed:%"PRIu32" - tmpu32:%"PRIu32, needed, tmpu32);
d5c737
+	if (sub(needed, tmpu32, &needed))
d5c737
+		goto overflow;
d5c737
+	debug("needed -> %"PRIu32, needed);
d5c737
+
d5c737
+	debug("datasz:%zu needed: %"PRIu32, datasz, needed);
d5c737
+	if (datasz < needed) {
d5c737
+		debug("needed: %"PRIu32" datasz: %zd -> returning needed datasz %"PRIu32,
d5c737
+			  needed, datasz, needed);
d5c737
+		return needed;
d5c737
+	}
d5c737
+
d5c737
+	*(uint32_t *)ptr = namesz;
d5c737
+	ptr += sizeof (uint32_t);
d5c737
+
d5c737
+	*(uint32_t *)ptr = var->data_size;
d5c737
+	ptr += sizeof (uint32_t);
d5c737
+
d5c737
+	ptr += namesz;
d5c737
+
d5c737
+	memcpy(ptr, var->guid, sizeof (efi_guid_t));
d5c737
+	ptr += sizeof(efi_guid_t);
d5c737
+
d5c737
+	*(uint32_t *)ptr = var->attrs;
d5c737
+	ptr += sizeof (uint32_t);
d5c737
+
d5c737
+	memcpy(ptr, var->data, var->data_size);
d5c737
+	ptr += var->data_size;
d5c737
+
d5c737
+	crc = efi_crc32(data, needed - sizeof(uint32_t));
d5c737
+	debug("efi_crc32(%p, %lu) -> 0x%"PRIx32,
d5c737
+	      data, needed - sizeof(uint32_t), crc);
d5c737
+	*(uint32_t *)ptr = crc;
d5c737
+
d5c737
+	return needed;
d5c737
+}
d5c737
+
d5c737
+ssize_t NONNULL(1) PUBLIC
d5c737
+efi_variable_export(efi_variable_t *var, uint8_t *data, size_t datasz)
d5c737
+{
d5c737
+	uint32_t tmpu32;
d5c737
+	ssize_t tmpssz;
d5c737
+	uint32_t namesz;
d5c737
+	uint32_t needed = sizeof (uint32_t)		/* magic */
d5c737
+			+ sizeof (uint32_t)		/* version */
d5c737
+			+ sizeof (uint64_t)		/* attr */
d5c737
+			+ sizeof (efi_guid_t)		/* guid */
d5c737
+			+ sizeof (uint32_t)		/* name_len */
d5c737
+			+ sizeof (uint32_t)		/* data_len */
d5c737
+			+ 2				/* name */
d5c737
+			+ 1				/* data */
d5c737
+			+ 4;				/* crc32 */
d5c737
+	uint8_t *ptr;
d5c737
+	uint32_t crc;
d5c737
+
d5c737
+	if (!var) {
d5c737
+		errno = EINVAL;
d5c737
+		efi_error("var cannot be NULL");
d5c737
+		return -1;
d5c737
+	}
d5c737
+	if (!var->name) {
d5c737
+		errno = EINVAL;
d5c737
+		efi_error("var->name cannot be NULL");
d5c737
+		return -1;
d5c737
+	}
d5c737
+	if (!var->data) {
d5c737
+		errno = EINVAL;
d5c737
+		efi_error("var->data cannot be NULL");
d5c737
+		return -1;
d5c737
+	}
d5c737
+
d5c737
+	debug("data: %p datasz: %zu", data, datasz);
d5c737
+
d5c737
+	namesz = utf8size(var->name, -1);
d5c737
+	debug("sizeof(uint16_t):%zd * namesz:%"PRIu32, sizeof(uint16_t), namesz);
d5c737
+	if (mul(sizeof (uint16_t), namesz, &namesz)) {
d5c737
+overflow:
d5c737
+		errno = EOVERFLOW;
d5c737
+		efi_error("arithmetic overflow computing name size");
d5c737
+		return -1;
d5c737
+	}
d5c737
+	debug("namesz -> %"PRIu32, namesz);
d5c737
+
d5c737
+	/*
d5c737
+	 * Remove our stand-ins for name size and data size before we add
d5c737
+	 * them back in.
d5c737
+	 */
d5c737
+	needed -= 3;
d5c737
+
d5c737
+	debug("needed:%"PRIu32" + namesz:%"PRIu32, needed, namesz);
d5c737
+	if (add(needed, namesz, &needed))
d5c737
+		goto overflow;
d5c737
+	debug("needed -> %"PRIu32, needed);
d5c737
+
d5c737
+	debug("needed:%"PRIu32" + var->data_size:%zd", needed, var->data_size);
d5c737
+	if (add(needed, var->data_size, &needed))
d5c737
+		goto overflow;
d5c737
+	debug("needed -> %"PRIu32, needed);
d5c737
+
d5c737
+	if (!data || datasz == 0) {
d5c737
+		debug("data: %p datasz: %zd -> returning needed datasz %"PRIu32,
d5c737
+		      data, datasz, needed);
d5c737
+		return needed;
d5c737
+	}
d5c737
+
d5c737
+	debug("datasz:%zu needed: %"PRIu32, datasz, needed);
d5c737
+	if (datasz < needed) {
d5c737
+		efi_error("needed: %"PRIu32" datasz: %zd -> returning needed datasz %zd",
d5c737
+			  needed, datasz, needed - datasz);
d5c737
+		return needed - datasz;
d5c737
+	}
d5c737
+
d5c737
+	ptr = data;
d5c737
 
d5c737
 	*(uint32_t *)ptr = EFIVAR_MAGIC;
d5c737
 	ptr += sizeof (uint32_t);
d5c737
@@ -181,21 +569,51 @@ efi_variable_export(efi_variable_t *var, uint8_t *data, size_t size)
d5c737
 	memcpy(ptr, var->guid, sizeof (efi_guid_t));
d5c737
 	ptr += sizeof (efi_guid_t);
d5c737
 
d5c737
-	*(uint32_t *)ptr = (uint32_t)(sizeof (char16_t) * name_len);
d5c737
+	tmpssz = utf8_to_ucs2(ptr + 8, datasz - 8, true, var->name);
d5c737
+	if (tmpssz < 0) {
d5c737
+		efi_error("UTF-8 to UCS-2 conversion failed");
d5c737
+		return -1;
d5c737
+	}
d5c737
+	tmpu32 = tmpssz;
d5c737
+	tmpu32 *= sizeof(uint16_t);
d5c737
+
d5c737
+	debug("namesz:%"PRIu32" - tmpu32:%"PRIu32, namesz, tmpu32);
d5c737
+	if (sub(namesz, tmpu32, &tmpu32))
d5c737
+		goto overflow;
d5c737
+	debug("tmpu32 -> %"PRIu32, tmpu32);
d5c737
+
d5c737
+	debug("needed:%"PRIu32" - tmpu32:%"PRIu32, needed, tmpu32);
d5c737
+	if (sub(needed, tmpu32, &needed))
d5c737
+		goto overflow;
d5c737
+	debug("needed -> %"PRIu32, needed);
d5c737
+
d5c737
+	debug("namesz:%"PRIu32" - tmpu32:%"PRIu32, namesz, tmpu32);
d5c737
+	if (sub(namesz, tmpu32, &namesz))
d5c737
+		goto overflow;
d5c737
+	debug("namesz -> %"PRIu32, namesz);
d5c737
+
d5c737
+	debug("datasz:%zu needed: %"PRIu32, datasz, needed);
d5c737
+	if (datasz < needed) {
d5c737
+		efi_error("needed: %"PRIu32" datasz: %zd -> returning needed datasz %zd",
d5c737
+			  needed, datasz, needed - datasz);
d5c737
+		return needed - datasz;
d5c737
+	}
d5c737
+
d5c737
+	*(uint32_t *)ptr = namesz;
d5c737
 	ptr += sizeof (uint32_t);
d5c737
 
d5c737
 	*(uint32_t *)ptr = var->data_size;
d5c737
 	ptr += sizeof (uint32_t);
d5c737
 
d5c737
-	for (uint32_t i = 0; i < name_len; i++) {
d5c737
-		*(char16_t *)ptr = var->name[i];
d5c737
-		ptr += sizeof (char16_t);
d5c737
-	}
d5c737
+	ptr += namesz;
d5c737
 
d5c737
 	memcpy(ptr, var->data, var->data_size);
d5c737
 	ptr += var->data_size;
d5c737
 
d5c737
-	*(uint32_t *)ptr = EFIVAR_MAGIC;
d5c737
+	crc = efi_crc32(data, needed - sizeof(uint32_t));
d5c737
+	debug("efi_crc32(%p, %lu) -> 0x%"PRIx32,
d5c737
+	      data, needed - sizeof(uint32_t), crc);
d5c737
+	*(uint32_t *)ptr = crc;
d5c737
 
d5c737
 	return needed;
d5c737
 }
d5c737
diff --git a/src/gpt.c b/src/gpt.c
d5c737
index aa4055b9812..8babafeb588 100644
d5c737
--- a/src/gpt.c
d5c737
+++ b/src/gpt.c
d5c737
@@ -48,24 +48,6 @@ struct blkdev_ioctl_param {
d5c737
 	char * block_contents;
d5c737
 };
d5c737
 
d5c737
-/**
d5c737
- * efi_crc32() - EFI version of crc32 function
d5c737
- * @buf: buffer to calculate crc32 of
d5c737
- * @len - length of buf
d5c737
- *
d5c737
- * Description: Returns EFI-style CRC32 value for @buf
d5c737
- *
d5c737
- * This function uses the little endian Ethernet polynomial
d5c737
- * but seeds the function with ~0, and xor's with ~0 at the end.
d5c737
- * Note, the EFI Specification, v1.02, has a reference to
d5c737
- * Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
d5c737
- */
d5c737
-static inline uint32_t
d5c737
-efi_crc32(const void *buf, unsigned long len)
d5c737
-{
d5c737
-	return (crc32(buf, len, ~0L) ^ ~0L);
d5c737
-}
d5c737
-
d5c737
 /**
d5c737
  * is_pmbr_valid(): test Protective MBR for validity
d5c737
  * @mbr: pointer to a legacy mbr structure
d5c737
diff --git a/src/include/efivar/efivar.h b/src/include/efivar/efivar.h
d5c737
index 729b6fe80f7..8ad14b9be57 100644
d5c737
--- a/src/include/efivar/efivar.h
d5c737
+++ b/src/include/efivar/efivar.h
d5c737
@@ -139,6 +139,9 @@ extern ssize_t efi_variable_import(uint8_t *data, size_t size,
d5c737
 extern ssize_t efi_variable_export(efi_variable_t *var, uint8_t *data,
d5c737
 				size_t size)
d5c737
 			__attribute__((__nonnull__ (1)));
d5c737
+extern ssize_t efi_variable_export_dmpstore(efi_variable_t *var, uint8_t *data,
d5c737
+				size_t size)
d5c737
+			__attribute__((__nonnull__ (1)));
d5c737
 
d5c737
 extern efi_variable_t *efi_variable_alloc(void)
d5c737
 			__attribute__((__visibility__ ("default")));
d5c737
-- 
d5c737
2.26.2
d5c737