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