Merge pull request #34717 from anonymix007/fundamental-boot-changes

Fundamental and boot changes for multi-dt UKIs
This commit is contained in:
Lennart Poettering
2024-10-11 17:55:06 +02:00
committed by GitHub
13 changed files with 339 additions and 213 deletions
+1
View File
@@ -23,6 +23,7 @@
#include "sbat.h"
#include "secure-boot.h"
#include "shim.h"
#include "smbios.h"
#include "ticks.h"
#include "tpm2-pcr.h"
#include "uki.h"
+2
View File
@@ -68,6 +68,8 @@ typedef uint64_t EFI_PHYSICAL_ADDRESS;
# error Unsupported pointer size
#endif
#define EFI_STATUS_IS_ERROR(s) (((s) & EFI_ERROR_MASK) != 0)
#define EFIWARN(s) ((EFI_STATUS) s)
#define EFIERR(s) ((EFI_STATUS) (s | EFI_ERROR_MASK))
+3 -4
View File
@@ -2,7 +2,6 @@
#include "log.h"
#include "proto/rng.h"
#include "proto/simple-text-io.h"
#include "util.h"
static unsigned log_count = 0;
@@ -32,14 +31,14 @@ void efi_assert(const char *expr, const char *file, unsigned line, const char *f
freeze();
}
EFI_STATUS log_internal(EFI_STATUS status, const char *format, ...) {
EFI_STATUS log_internal(EFI_STATUS status, uint8_t text_color, const char *format, ...) {
assert(format);
int32_t attr = ST->ConOut->Mode->Attribute;
if (ST->ConOut->Mode->CursorColumn > 0)
ST->ConOut->OutputString(ST->ConOut, (char16_t *) u"\r\n");
ST->ConOut->SetAttribute(ST->ConOut, EFI_TEXT_ATTR(EFI_LIGHTRED, EFI_BLACK));
ST->ConOut->SetAttribute(ST->ConOut, EFI_TEXT_ATTR(text_color, EFI_BLACK));
va_list ap;
va_start(ap, format);
@@ -58,7 +57,7 @@ void log_hexdump(const char16_t *prefix, const void *data, size_t size) {
/* Debugging helper — please keep this around, even if not used */
_cleanup_free_ char16_t *hex = hexdump(data, size);
log_internal(EFI_SUCCESS, "%ls[%zu]: %ls", prefix, size, hex);
log_internal(EFI_SUCCESS, EFI_LIGHTRED, "%ls[%zu]: %ls", prefix, size, hex);
}
#endif
+8 -5
View File
@@ -2,6 +2,7 @@
#pragma once
#include "efi-string.h"
#include "proto/simple-text-io.h"
#if defined __has_attribute
# if __has_attribute(no_stack_protector)
@@ -21,11 +22,13 @@ __attribute__((no_stack_protector, noinline)) void __stack_chk_guard_init(void);
_noreturn_ void freeze(void);
void log_wait(void);
_gnu_printf_(2, 3) EFI_STATUS log_internal(EFI_STATUS status, const char *format, ...);
#define log_error_status(status, ...) log_internal(status, __VA_ARGS__)
#define log_error(...) log_internal(EFI_INVALID_PARAMETER, __VA_ARGS__)
#define log_oom() log_internal(EFI_OUT_OF_RESOURCES, "Out of memory.")
#define log_trace() log_internal(EFI_SUCCESS, "%s:%i@%s", __FILE__, __LINE__, __func__)
_gnu_printf_(3, 4) EFI_STATUS log_internal(EFI_STATUS status, uint8_t text_color, const char *format, ...);
#define log_debug(...) log_internal(EFI_SUCCESS, EFI_LIGHTGRAY, __VA_ARGS__)
#define log_info(...) log_internal(EFI_SUCCESS, EFI_WHITE, __VA_ARGS__)
#define log_error_status(status, ...) log_internal(status, EFI_LIGHTRED, __VA_ARGS__)
#define log_error(...) log_internal(EFI_INVALID_PARAMETER, EFI_LIGHTRED, __VA_ARGS__)
#define log_oom() log_internal(EFI_OUT_OF_RESOURCES, EFI_LIGHTRED, "Out of memory.")
#define log_trace() log_internal(EFI_SUCCESS, EFI_LIGHTRED, "%s:%i@%s", __FILE__, __LINE__, __func__)
#ifdef EFI_DEBUG
void log_hexdump(const char16_t *prefix, const void *data, size_t size);
+1
View File
@@ -270,6 +270,7 @@ libefi_sources = files(
'random-seed.c',
'secure-boot.c',
'shim.c',
'smbios.c',
'ticks.c',
'util.c',
'vmm.c',
+250
View File
@@ -0,0 +1,250 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "efi-string.h"
#include "efivars.h"
#include "proto/device-path.h"
#include "smbios.h"
#include "string-util-fundamental.h"
#include "util.h"
#define SMBIOS_TABLE_GUID \
GUID_DEF(0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
#define SMBIOS3_TABLE_GUID \
GUID_DEF(0xf2fd1544, 0x9794, 0x4a2c, 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94)
typedef struct {
uint8_t anchor_string[4];
uint8_t entry_point_structure_checksum;
uint8_t entry_point_length;
uint8_t major_version;
uint8_t minor_version;
uint16_t max_structure_size;
uint8_t entry_point_revision;
uint8_t formatted_area[5];
uint8_t intermediate_anchor_string[5];
uint8_t intermediate_checksum;
uint16_t table_length;
uint32_t table_address;
uint16_t number_of_smbios_structures;
uint8_t smbios_bcd_revision;
} _packed_ SmbiosEntryPoint;
typedef struct {
uint8_t anchor_string[5];
uint8_t entry_point_structure_checksum;
uint8_t entry_point_length;
uint8_t major_version;
uint8_t minor_version;
uint8_t docrev;
uint8_t entry_point_revision;
uint8_t reserved;
uint32_t table_maximum_size;
uint64_t table_address;
} _packed_ Smbios3EntryPoint;
typedef struct {
uint8_t type;
uint8_t length;
uint8_t handle[2];
} _packed_ SmbiosHeader;
typedef struct {
SmbiosHeader header;
uint8_t vendor;
uint8_t bios_version;
uint16_t bios_segment;
uint8_t bios_release_date;
uint8_t bios_size;
uint64_t bios_characteristics;
uint8_t bios_characteristics_ext[2];
} _packed_ SmbiosTableType0;
typedef struct {
SmbiosHeader header;
uint8_t manufacturer;
uint8_t product_name;
uint8_t version;
uint8_t serial_number;
EFI_GUID uuid;
uint8_t wake_up_type;
uint8_t sku_number;
uint8_t family;
} _packed_ SmbiosTableType1;
typedef struct {
SmbiosHeader header;
uint8_t manufacturer;
uint8_t product_name;
uint8_t version;
uint8_t serial_number;
} _packed_ SmbiosTableType2;
typedef struct {
SmbiosHeader header;
uint8_t count;
char contents[];
} _packed_ SmbiosTableType11;
static const void *find_smbios_configuration_table(uint64_t *ret_size) {
assert(ret_size);
const Smbios3EntryPoint *entry3 = find_configuration_table(MAKE_GUID_PTR(SMBIOS3_TABLE));
if (entry3 && memcmp(entry3->anchor_string, "_SM3_", 5) == 0 &&
entry3->entry_point_length <= sizeof(*entry3)) {
*ret_size = entry3->table_maximum_size;
return PHYSICAL_ADDRESS_TO_POINTER(entry3->table_address);
}
const SmbiosEntryPoint *entry = find_configuration_table(MAKE_GUID_PTR(SMBIOS_TABLE));
if (entry && memcmp(entry->anchor_string, "_SM_", 4) == 0 &&
entry->entry_point_length <= sizeof(*entry)) {
*ret_size = entry->table_length;
return PHYSICAL_ADDRESS_TO_POINTER(entry->table_address);
}
return NULL;
}
static const SmbiosHeader *get_smbios_table(uint8_t type, size_t min_size, uint64_t *ret_size_left) {
uint64_t size = 0;
const uint8_t *p = find_smbios_configuration_table(&size);
if (!p)
return NULL;
for (;;) {
if (size < sizeof(SmbiosHeader))
return NULL;
const SmbiosHeader *header = (const SmbiosHeader *) p;
/* End of table. */
if (header->type == 127)
return NULL;
if (size < header->length)
return NULL;
if (header->type == type) {
/* Table is smaller than the minimum expected size? Refuse */
if (header->length < min_size)
return NULL;
if (ret_size_left)
*ret_size_left = size;
return header; /* Yay! */
}
/* Skip over formatted area. */
size -= header->length;
p += header->length;
/* Special case: if there are no strings appended, we'll see two NUL bytes, skip over them */
if (size >= 2 && p[0] == 0 && p[1] == 0) {
size -= 2;
p += 2;
continue;
}
/* Skip over a populated string table. */
bool first = true;
for (;;) {
const uint8_t *e = memchr(p, 0, size);
if (!e)
return NULL;
if (!first && e == p) {/* Double NUL byte means we've reached the end of the string table. */
p++;
size--;
break;
}
size -= e + 1 - p;
p = e + 1;
first = false;
}
}
return NULL;
}
bool smbios_in_hypervisor(void) {
/* Look up BIOS Information (Type 0). */
const SmbiosTableType0 *type0 = (const SmbiosTableType0 *) get_smbios_table(0, sizeof(SmbiosTableType0), /* left= */ NULL);
if (!type0)
return false;
/* Bit 4 of 2nd BIOS characteristics extension bytes indicates virtualization. */
return FLAGS_SET(type0->bios_characteristics_ext[1], 1 << 4);
}
const char* smbios_find_oem_string(const char *name) {
uint64_t left;
assert(name);
const SmbiosTableType11 *type11 = (const SmbiosTableType11 *) get_smbios_table(11, sizeof(SmbiosTableType11), &left);
if (!type11)
return NULL;
const char *s = type11->contents;
assert(left >= type11->header.length); /* get_smbios_table() already validated this */
left -= type11->header.length;
const char *limit = s + left;
for (const char *p = s; p < limit; ) {
const char *e = memchr(p, 0, limit - p);
if (!e || e == p) /* Double NUL byte means we've reached the end of the OEM strings. */
break;
const char *eq = startswith8(p, name);
if (eq && *eq == '=')
return eq + 1;
p = e + 1;
}
return NULL;
}
static const char* smbios_get_string(const SmbiosHeader *header, size_t nr, uint64_t left) {
assert(header);
const char *s = (const char *) header;
/* We assume that get_smbios_table() already validated the header size making some superficial sense */
assert(left >= header->length);
s += header->length;
left -= header->length;
size_t index = 1;
for (const char *p = s, *limit = s + left; index <= nr && p < limit; index++) {
const char *e = memchr(p, 0, limit - p);
if (!e || e == p) /* Double NUL byte means we've reached the end of the strings. */
break;
if (index == nr)
return p;
p = e + 1;
}
return NULL;
}
void smbios_raw_info_populate(RawSmbiosInfo *ret_info) {
assert(ret_info);
uint64_t left;
const SmbiosTableType1 *type1 = (const SmbiosTableType1 *) get_smbios_table(1, sizeof(SmbiosTableType1), &left);
if (type1) {
ret_info->manufacturer = smbios_get_string(&type1->header, type1->manufacturer, left);
ret_info->product_name = smbios_get_string(&type1->header, type1->product_name, left);
ret_info->product_sku = smbios_get_string(&type1->header, type1->sku_number, left);
ret_info->family = smbios_get_string(&type1->header, type1->family, left);
}
const SmbiosTableType2 *type2 = (const SmbiosTableType2 *) get_smbios_table(2, sizeof(SmbiosTableType2), &left);
if (type2) {
ret_info->baseboard_manufacturer = smbios_get_string(&type2->header, type2->manufacturer, left);
ret_info->baseboard_product = smbios_get_string(&type2->header, type2->product_name, left);
}
}
+19
View File
@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "efi.h"
bool smbios_in_hypervisor(void);
const char* smbios_find_oem_string(const char *name);
typedef struct RawSmbiosInfo {
const char *manufacturer;
const char *product_name;
const char *product_sku;
const char *family;
const char *baseboard_product;
const char *baseboard_manufacturer;
} RawSmbiosInfo;
void smbios_raw_info_populate(RawSmbiosInfo *ret_info);
+1
View File
@@ -17,6 +17,7 @@
#include "sbat.h"
#include "secure-boot.h"
#include "shim.h"
#include "smbios.h"
#include "splash.h"
#include "tpm2-pcr.h"
#include "uki.h"
+24
View File
@@ -2,8 +2,10 @@
#pragma once
#include "efi.h"
#include "efi-string.h"
#include "log.h"
#include "proto/file-io.h"
#include "memory-util-fundamental.h"
#include "string-util-fundamental.h"
/* This is provided by the linker. */
@@ -31,6 +33,19 @@ static inline void freep(void *p) {
_malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_
void *xmalloc(size_t size);
_malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_
static inline void *xcalloc(size_t size) {
void *t = xmalloc(size);
memzero(t, size);
return t;
}
_malloc_ _alloc_(1, 2) _returns_nonnull_ _warn_unused_result_
static inline void *xcalloc_multiply(size_t n, size_t size) {
assert_se(MUL_ASSIGN_SAFE(&size, n));
return xcalloc(size);
}
_malloc_ _alloc_(1, 2) _returns_nonnull_ _warn_unused_result_
static inline void *xmalloc_multiply(size_t n, size_t size) {
assert_se(MUL_ASSIGN_SAFE(&size, n));
@@ -188,3 +203,12 @@ static inline bool efi_guid_equal(const EFI_GUID *a, const EFI_GUID *b) {
void *find_configuration_table(const EFI_GUID *guid);
char16_t *get_extra_dir(const EFI_DEVICE_PATH *file_path);
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define be32toh(x) __builtin_bswap32(x)
#else
# error "Unexpected byte order in EFI mode?"
#endif
#define bswap_16(x) __builtin_bswap16(x)
#define bswap_32(x) __builtin_bswap32(x)
+1 -180
View File
@@ -10,6 +10,7 @@
#include "efi-string.h"
#include "efivars.h"
#include "proto/device-path.h"
#include "smbios.h"
#include "string-util-fundamental.h"
#include "util.h"
#include "vmm.h"
@@ -135,156 +136,6 @@ static bool cpuid_in_hypervisor(void) {
return false;
}
#define SMBIOS_TABLE_GUID \
GUID_DEF(0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
#define SMBIOS3_TABLE_GUID \
GUID_DEF(0xf2fd1544, 0x9794, 0x4a2c, 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94)
typedef struct {
uint8_t anchor_string[4];
uint8_t entry_point_structure_checksum;
uint8_t entry_point_length;
uint8_t major_version;
uint8_t minor_version;
uint16_t max_structure_size;
uint8_t entry_point_revision;
uint8_t formatted_area[5];
uint8_t intermediate_anchor_string[5];
uint8_t intermediate_checksum;
uint16_t table_length;
uint32_t table_address;
uint16_t number_of_smbios_structures;
uint8_t smbios_bcd_revision;
} _packed_ SmbiosEntryPoint;
typedef struct {
uint8_t anchor_string[5];
uint8_t entry_point_structure_checksum;
uint8_t entry_point_length;
uint8_t major_version;
uint8_t minor_version;
uint8_t docrev;
uint8_t entry_point_revision;
uint8_t reserved;
uint32_t table_maximum_size;
uint64_t table_address;
} _packed_ Smbios3EntryPoint;
typedef struct {
uint8_t type;
uint8_t length;
uint8_t handle[2];
} _packed_ SmbiosHeader;
typedef struct {
SmbiosHeader header;
uint8_t vendor;
uint8_t bios_version;
uint16_t bios_segment;
uint8_t bios_release_date;
uint8_t bios_size;
uint64_t bios_characteristics;
uint8_t bios_characteristics_ext[2];
} _packed_ SmbiosTableType0;
typedef struct {
SmbiosHeader header;
uint8_t count;
char contents[];
} _packed_ SmbiosTableType11;
static const void *find_smbios_configuration_table(uint64_t *ret_size) {
assert(ret_size);
const Smbios3EntryPoint *entry3 = find_configuration_table(MAKE_GUID_PTR(SMBIOS3_TABLE));
if (entry3 && memcmp(entry3->anchor_string, "_SM3_", 5) == 0 &&
entry3->entry_point_length <= sizeof(*entry3)) {
*ret_size = entry3->table_maximum_size;
return PHYSICAL_ADDRESS_TO_POINTER(entry3->table_address);
}
const SmbiosEntryPoint *entry = find_configuration_table(MAKE_GUID_PTR(SMBIOS_TABLE));
if (entry && memcmp(entry->anchor_string, "_SM_", 4) == 0 &&
entry->entry_point_length <= sizeof(*entry)) {
*ret_size = entry->table_length;
return PHYSICAL_ADDRESS_TO_POINTER(entry->table_address);
}
return NULL;
}
static const SmbiosHeader *get_smbios_table(uint8_t type, size_t min_size, uint64_t *ret_size_left) {
uint64_t size = 0;
const uint8_t *p = find_smbios_configuration_table(&size);
if (!p)
return NULL;
for (;;) {
if (size < sizeof(SmbiosHeader))
return NULL;
const SmbiosHeader *header = (const SmbiosHeader *) p;
/* End of table. */
if (header->type == 127)
return NULL;
if (size < header->length)
return NULL;
if (header->type == type) {
/* Table is smaller than the minimum expected size? Refuse */
if (header->length < min_size)
return NULL;
if (ret_size_left)
*ret_size_left = size;
return header; /* Yay! */
}
/* Skip over formatted area. */
size -= header->length;
p += header->length;
/* Special case: if there are no strings appended, we'll see two NUL bytes, skip over them */
if (size >= 2 && p[0] == 0 && p[1] == 0) {
size -= 2;
p += 2;
continue;
}
/* Skip over a populated string table. */
bool first = true;
for (;;) {
const uint8_t *e = memchr(p, 0, size);
if (!e)
return NULL;
if (!first && e == p) {/* Double NUL byte means we've reached the end of the string table. */
p++;
size--;
break;
}
size -= e + 1 - p;
p = e + 1;
first = false;
}
}
return NULL;
}
static bool smbios_in_hypervisor(void) {
/* Look up BIOS Information (Type 0). */
const SmbiosTableType0 *type0 = (const SmbiosTableType0 *) get_smbios_table(0, sizeof(SmbiosTableType0), /* left= */ NULL);
if (!type0)
return false;
/* Bit 4 of 2nd BIOS characteristics extension bytes indicates virtualization. */
return FLAGS_SET(type0->bios_characteristics_ext[1], 1 << 4);
}
bool in_hypervisor(void) {
static int cache = -1;
if (cache >= 0)
@@ -294,36 +145,6 @@ bool in_hypervisor(void) {
return cache;
}
const char* smbios_find_oem_string(const char *name) {
uint64_t left;
assert(name);
const SmbiosTableType11 *type11 = (const SmbiosTableType11 *) get_smbios_table(11, sizeof(SmbiosTableType11), &left);
if (!type11)
return NULL;
const char *s = type11->contents;
assert(left >= type11->header.length); /* get_smbios_table() already validated this */
left -= type11->header.length;
const char *limit = s + left;
for (const char *p = s; p < limit; ) {
const char *e = memchr(p, 0, limit - p);
if (!e || e == p) /* Double NUL byte means we've reached the end of the OEM strings. */
break;
const char *eq = startswith8(p, name);
if (eq && *eq == '=')
return eq + 1;
p = e + 1;
}
return NULL;
}
#if defined(__i386__) || defined(__x86_64__)
static uint32_t cpuid_leaf(uint32_t eax, char ret_sig[static 13], bool swapped) {
/* zero-init as some queries explicitly require subleaf == 0 */
-2
View File
@@ -9,5 +9,3 @@ EFI_STATUS vmm_open(EFI_HANDLE *ret_vmm_dev, EFI_FILE **ret_vmm_dir);
bool in_hypervisor(void);
bool is_confidential_vm(void);
const char* smbios_find_oem_string(const char *name);
+13
View File
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#if !SD_BOOT
# include <stdint.h>
/* Matches EFI API definition of the same structure for userspace */
typedef struct {
uint32_t Data1;
uint16_t Data2;
uint16_t Data3;
uint8_t Data4[8];
} EFI_GUID;
#endif
+16 -22
View File
@@ -5,6 +5,7 @@
#include "alloc-util.h"
#include "dirent-util.h"
#include "efi-api.h"
#include "efi-fundamental.h"
#include "efivars.h"
#include "fd-util.h"
#include "fileio.h"
@@ -523,29 +524,22 @@ bool efi_has_tpm2(void) {
#endif
struct efi_guid {
uint32_t u1;
uint16_t u2;
uint16_t u3;
uint8_t u4[8];
} _packed_;
sd_id128_t efi_guid_to_id128(const void *guid) {
const struct efi_guid *uuid = ASSERT_PTR(guid); /* cast is safe, because struct efi_guid is packed */
const EFI_GUID *uuid = ASSERT_PTR(guid); /* cast is safe, because struct efi_guid is packed */
sd_id128_t id128;
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[0] = (uuid->Data1 >> 24) & 0xff;
id128.bytes[1] = (uuid->Data1 >> 16) & 0xff;
id128.bytes[2] = (uuid->Data1 >> 8) & 0xff;
id128.bytes[3] = uuid->Data1 & 0xff;
id128.bytes[4] = (uuid->u2 >> 8) & 0xff;
id128.bytes[5] = uuid->u2 & 0xff;
id128.bytes[4] = (uuid->Data2 >> 8) & 0xff;
id128.bytes[5] = uuid->Data2 & 0xff;
id128.bytes[6] = (uuid->u3 >> 8) & 0xff;
id128.bytes[7] = uuid->u3 & 0xff;
id128.bytes[6] = (uuid->Data3 >> 8) & 0xff;
id128.bytes[7] = uuid->Data3 & 0xff;
memcpy(&id128.bytes[8], uuid->u4, sizeof(uuid->u4));
memcpy(&id128.bytes[8], uuid->Data4, sizeof(uuid->Data4));
return id128;
}
@@ -553,11 +547,11 @@ sd_id128_t efi_guid_to_id128(const void *guid) {
void efi_id128_to_guid(sd_id128_t id, void *ret_guid) {
assert(ret_guid);
struct efi_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],
EFI_GUID uuid = {
.Data1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3],
.Data2 = id.bytes[4] << 8 | id.bytes[5],
.Data3 = id.bytes[6] << 8 | id.bytes[7],
};
memcpy(uuid.u4, id.bytes+8, sizeof(uuid.u4));
memcpy(uuid.Data4, id.bytes+8, sizeof(uuid.Data4));
memcpy(ret_guid, &uuid, sizeof(uuid));
}