summaryrefslogtreecommitdiff
path: root/src/shared/efivars.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/efivars.c')
-rw-r--r--src/shared/efivars.c134
1 files changed, 76 insertions, 58 deletions
diff --git a/src/shared/efivars.c b/src/shared/efivars.c
index cb9e13c15f..26f905bfaa 100644
--- a/src/shared/efivars.c
+++ b/src/shared/efivars.c
@@ -40,11 +40,17 @@
#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
-struct boot_option {
- uint32_t attr;
- uint16_t path_len;
- uint16_t title[];
-} _packed_;
+#define boot_option__contents { \
+ uint32_t attr; \
+ uint16_t path_len; \
+ uint16_t title[]; \
+ }
+
+struct boot_option boot_option__contents;
+struct boot_option__packed boot_option__contents _packed_;
+assert_cc(offsetof(struct boot_option, title) == offsetof(struct boot_option__packed, title));
+/* sizeof(struct boot_option) != sizeof(struct boot_option__packed), so
+ * the *size* of the structure should not be used anywhere below. */
struct drive_path {
uint32_t part_nr;
@@ -55,15 +61,19 @@ struct drive_path {
uint8_t signature_type;
} _packed_;
-struct device_path {
- uint8_t type;
- uint8_t sub_type;
- uint16_t length;
- union {
- uint16_t path[0];
- struct drive_path drive;
- };
-} _packed_;
+#define device_path__contents { \
+ uint8_t type; \
+ uint8_t sub_type; \
+ uint16_t length; \
+ union { \
+ uint16_t path[0]; \
+ struct drive_path drive; \
+ }; \
+ }
+
+struct device_path device_path__contents;
+struct device_path__packed device_path__contents _packed_;
+assert_cc(sizeof(struct device_path) == sizeof(struct device_path__packed));
bool is_efi_boot(void) {
if (detect_container() > 0)
@@ -354,32 +364,46 @@ int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *v)
return efi_set_variable(vendor, name, u16, (char16_strlen(u16) + 1) * sizeof(char16_t));
}
-static size_t utf16_size(const uint16_t *s) {
+static ssize_t utf16_size(const uint16_t *s, size_t buf_len_bytes) {
size_t l = 0;
- while (s[l] > 0)
+ /* Returns the size of the string in bytes without the terminating two zero bytes */
+
+ if (buf_len_bytes % sizeof(uint16_t) != 0)
+ return -EINVAL;
+
+ while (l < buf_len_bytes / sizeof(uint16_t)) {
+ if (s[l] == 0)
+ return (l + 1) * sizeof(uint16_t);
l++;
+ }
- return (l+1) * sizeof(uint16_t);
+ return -EINVAL; /* The terminator was not found */
}
+struct guid {
+ uint32_t u1;
+ uint16_t u2;
+ uint16_t u3;
+ uint8_t u4[8];
+} _packed_;
+
static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
- struct uuid {
- uint32_t u1;
- uint16_t u2;
- uint16_t u3;
- uint8_t u4[8];
- } _packed_;
- const struct uuid *uuid = guid;
-
- id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
- id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
- id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
- id128->bytes[3] = (uuid->u1) & 0xff;
- id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
- id128->bytes[5] = (uuid->u2) & 0xff;
- id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
- id128->bytes[7] = (uuid->u3) & 0xff;
+ uint32_t u1;
+ uint16_t u2, u3;
+ const struct guid *uuid = guid;
+
+ memcpy(&u1, &uuid->u1, sizeof(uint32_t));
+ id128->bytes[0] = (u1 >> 24) & 0xff;
+ id128->bytes[1] = (u1 >> 16) & 0xff;
+ id128->bytes[2] = (u1 >> 8) & 0xff;
+ id128->bytes[3] = u1 & 0xff;
+ memcpy(&u2, &uuid->u2, sizeof(uint16_t));
+ id128->bytes[4] = (u2 >> 8) & 0xff;
+ id128->bytes[5] = u2 & 0xff;
+ memcpy(&u3, &uuid->u3, sizeof(uint16_t));
+ id128->bytes[6] = (u3 >> 8) & 0xff;
+ id128->bytes[7] = u3 & 0xff;
memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
}
@@ -394,7 +418,7 @@ int efi_get_boot_option(
_cleanup_free_ uint8_t *buf = NULL;
size_t l;
struct boot_option *header;
- size_t title_size;
+ ssize_t title_size;
_cleanup_free_ char *s = NULL, *p = NULL;
sd_id128_t p_uuid = SD_ID128_NULL;
int r;
@@ -406,13 +430,13 @@ int efi_get_boot_option(
r = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
if (r < 0)
return r;
- if (l < sizeof(struct boot_option))
+ if (l < offsetof(struct boot_option, title))
return -ENOENT;
header = (struct boot_option *)buf;
- title_size = utf16_size(header->title);
- if (title_size > l - offsetof(struct boot_option, title))
- return -EINVAL;
+ title_size = utf16_size(header->title, l - offsetof(struct boot_option, title));
+ if (title_size < 0)
+ return title_size;
if (title) {
s = utf16_to_utf8(header->title, title_size);
@@ -494,20 +518,14 @@ static void to_utf16(uint16_t *dest, const char *src) {
dest[i] = '\0';
}
-struct guid {
- uint32_t u1;
- uint16_t u2;
- uint16_t u3;
- uint8_t u4[8];
-} _packed_;
-
static void id128_to_efi_guid(sd_id128_t id, void *guid) {
- struct guid *uuid = guid;
-
- uuid->u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3];
- uuid->u2 = id.bytes[4] << 8 | id.bytes[5];
- uuid->u3 = id.bytes[6] << 8 | id.bytes[7];
- memcpy(uuid->u4, id.bytes+8, sizeof(uuid->u4));
+ struct guid uuid = {
+ .u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3],
+ .u2 = id.bytes[4] << 8 | id.bytes[5],
+ .u3 = id.bytes[6] << 8 | id.bytes[7],
+ };
+ memcpy(uuid.u4, id.bytes+8, sizeof(uuid.u4));
+ memcpy(guid, &uuid, sizeof(uuid));
}
static uint16_t *tilt_slashes(uint16_t *s) {
@@ -541,7 +559,7 @@ int efi_add_boot_option(
title_len = (strlen(title)+1) * 2;
path_len = (strlen(path)+1) * 2;
- buf = malloc0(sizeof(struct boot_option) + title_len +
+ buf = malloc0(offsetof(struct boot_option, title) + title_len +
sizeof(struct drive_path) +
sizeof(struct device_path) + path_len);
if (!buf)
@@ -561,12 +579,12 @@ int efi_add_boot_option(
devicep->type = MEDIA_DEVICE_PATH;
devicep->sub_type = MEDIA_HARDDRIVE_DP;
devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
- devicep->drive.part_nr = part;
- devicep->drive.part_start = pstart;
- devicep->drive.part_size = psize;
- devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
- devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
+ memcpy(&devicep->drive.part_nr, &part, sizeof(uint32_t));
+ memcpy(&devicep->drive.part_start, &pstart, sizeof(uint64_t));
+ memcpy(&devicep->drive.part_size, &psize, sizeof(uint64_t));
id128_to_efi_guid(part_uuid, devicep->drive.signature);
+ devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
+ devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
size += devicep->length;
/* path to loader */
@@ -630,7 +648,7 @@ int efi_set_boot_order(uint16_t *order, size_t n) {
return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t));
}
-static int boot_id_hex(const char s[4]) {
+static int boot_id_hex(const char s[static 4]) {
int id = 0, i;
for (i = 0; i < 4; i++)