chid_match: match UEFI firmware hwid entry with the current smbios data

UEFI firmware type hwids must be matched against the current hardware first.
This change implements that. Additionally, some extra validations on the hwids
entries have also been added.
This commit is contained in:
Ani Sinha
2026-06-20 15:14:40 +02:00
committed by Lennart Poettering
parent 19bd80e29a
commit 1f4f348c8e
3 changed files with 82 additions and 34 deletions
+26 -3
View File
@@ -121,12 +121,35 @@ EFI_STATUS chid_match(const void *hwid_buffer, size_t hwid_length, uint32_t matc
/* Count devices and check validity */
for (; (n_devices + 1) * sizeof(*devices) < hwid_length;) {
const Device *device = &devices[n_devices];
if (devices[n_devices].descriptor == DEVICE_DESCRIPTOR_EOL)
if (device->descriptor == DEVICE_DESCRIPTOR_EOL)
break;
if (!IN_SET(DEVICE_TYPE_FROM_DESCRIPTOR(devices[n_devices].descriptor),
DEVICE_TYPE_UEFI_FW, DEVICE_TYPE_DEVICETREE))
uint32_t device_type = DEVICE_TYPE_FROM_DESCRIPTOR(device->descriptor);
size_t name_off, off;
if (!IN_SET(device_type, DEVICE_TYPE_UEFI_FW, DEVICE_TYPE_DEVICETREE))
return EFI_UNSUPPORTED;
if (device_type == DEVICE_TYPE_DEVICETREE) {
off = device->devicetree.compatible_offset;
name_off = device->devicetree.name_offset;
} else if (device_type == DEVICE_TYPE_UEFI_FW) {
off = device->uefi_fw.fwid_offset;
name_off = device->uefi_fw.name_offset;
} else
assert_not_reached();
if (off >= hwid_length || name_off >= hwid_length)
return EFI_INVALID_PARAMETER;
/* check for NULL termination */
if (off && !memchr((const uint8_t *) hwid_buffer + off, 0, hwid_length - off))
return EFI_INVALID_PARAMETER;
if (name_off && !memchr((const uint8_t *) hwid_buffer + name_off, 0, hwid_length - name_off))
return EFI_INVALID_PARAMETER;
n_devices++;
}
+55 -30
View File
@@ -345,13 +345,14 @@ static void pe_locate_sections_internal(
}
}
static bool looking_for_dtbauto(const char *const section_names[]) {
static bool looking_for_dtbauto_or_efifw(const char *const section_names[]) {
assert(section_names);
for (size_t i = 0; section_names[i]; i++)
if (pe_section_name_equal(section_names[i], ".dtbauto"))
if (pe_section_name_equal(section_names[i], ".dtbauto") ||
pe_section_name_equal(section_names[i], ".efifw"))
return true;
return false;
return false;
}
static void pe_locate_sections(
@@ -361,7 +362,7 @@ static void pe_locate_sections(
size_t validate_base,
PeSectionVector sections[]) {
if (!looking_for_dtbauto(section_names))
if (!looking_for_dtbauto_or_efifw(section_names))
return pe_locate_sections_internal(
section_table,
n_section_table,
@@ -377,40 +378,64 @@ static void pe_locate_sections(
const void *hwids = NULL;
const Device *device = NULL;
if (!firmware_devicetree_exists()) {
/* Find HWIDs table and search for the current device */
static const char *const hwid_section_names[] = { ".hwids", NULL };
PeSectionVector hwids_section[1] = {};
/* Find HWIDs table and search for the current device */
static const char *const hwid_section_names[] = { ".hwids", NULL };
PeSectionVector hwids_section[1] = {};
pe_locate_sections_internal(
section_table,
n_section_table,
hwid_section_names,
validate_base,
/* device_table= */ NULL,
/* device= */ NULL,
hwids_section);
pe_locate_sections_internal(
section_table,
n_section_table,
hwid_section_names,
validate_base,
/* device_table= */ NULL,
/* device= */ NULL,
hwids_section);
if (PE_SECTION_VECTOR_IS_SET(hwids_section)) {
hwids = (const uint8_t *) SIZE_TO_PTR(validate_base) + hwids_section[0].memory_offset;
if (PE_SECTION_VECTOR_IS_SET(hwids_section)) {
hwids = (const uint8_t *) SIZE_TO_PTR(validate_base) + hwids_section[0].memory_offset;
EFI_STATUS err;
EFI_STATUS err = chid_match(hwids, hwids_section[0].memory_size, DEVICE_TYPE_DEVICETREE, &device);
if (err != EFI_SUCCESS) {
if (!firmware_devicetree_exists()) {
err = chid_match(hwids, hwids_section[0].memory_size, DEVICE_TYPE_DEVICETREE, &device);
if (err == EFI_SUCCESS)
pe_locate_sections_internal(
section_table,
n_section_table,
section_names,
validate_base,
hwids,
device,
sections);
else
log_full(err, err == EFI_NOT_FOUND ? LOG_DEBUG : LOG_ERR,
"HWID matching failed, no DT blob will be selected: %m");
hwids = NULL;
}
}
err = chid_match(hwids, hwids_section[0].memory_size, DEVICE_TYPE_UEFI_FW, &device);
if (err == EFI_SUCCESS)
pe_locate_sections_internal(
section_table,
n_section_table,
section_names,
validate_base,
hwids,
device,
sections);
else {
log_full(err, err == EFI_NOT_FOUND ? LOG_DEBUG : LOG_ERR,
"No UEFI FW will be selected: %m");
hwids = NULL;
device = NULL;
}
}
return pe_locate_sections_internal(
section_table,
n_section_table,
section_names,
validate_base,
hwids,
device,
sections);
section_table,
n_section_table,
section_names,
validate_base,
hwids,
device,
sections);
}
static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const PeFileHeader *pe) {
+1 -1
View File
@@ -599,7 +599,7 @@ static EFI_STATUS load_addons(
err = pe_memory_locate_sections(loaded_addon->ImageBase, unified_sections, sections);
if (err != EFI_SUCCESS) {
log_error_status(err,
"Unable to locate embedded .cmdline/.dtb/.dtbauto/.initrd/.ucode sections in %ls, ignoring: %m",
"Unable to locate embedded .cmdline/.dtb/.dtbauto/.efifw/.initrd/.ucode sections in %ls, ignoring: %m",
items[i]);
continue;
}