Re: [PATCH v2 3/7] firmware: dmi: Read additional information when decoding DMI table

Jean Delvare
2025-12-22T17:52:03Z

Hi Mario,

On Tue, 16 Dec 2025 06:33:50 -0600, Mario Limonciello (AMD) wrote:
> Type 40 entries (Additional information) are summarized in section
> 7.41 as part of the SMBIOS specification. Save these entries when
> decoding the DMI tables.
>
> Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>
> ---
> v2:
> * Drop some unneeded variables (LKP robot)
> * Allow any length strings, not just 5 and longer
> ---
> drivers/firmware/dmi_scan.c | 38 +++++++++++++++++++++++++++++++++++++
> include/linux/dmi.h | 7 +++++++
> 2 files changed, 45 insertions(+)
>
> diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
> index 80aded4c778bc..ec84fe3935c1e 100644
> --- a/drivers/firmware/dmi_scan.c
> +++ b/drivers/firmware/dmi_scan.c
> @@ -393,6 +393,40 @@ static void __init dmi_save_dev_pciaddr(int instance, int segment, int bus,
> list_add(&dev->dev.list, &dmi_devices);
> }
>
> +static void __init dmi_save_additional(const struct dmi_additional_info *info)
> +{
> + const u8 *data;
> + int i;
> +
> + if (!info || info->header.length < 5 + info->count * 5)

Evaluating the second condition will access info->count, which is not
guaranteed to exist if info->header.length < 5. Of course if the DMI
table is compliant, it will be fine, but you can't rely on
firmware-provided data being sane.

Second problem is that you seem to assume that every entry has size 5
bytes. The SMBIOS specification says that the minimum size is 6 bytes,
and the actual size is stored in the first byte of each entry. So you
can't validate the total length upfront. You need to check as you walk
the table that the next entry would fit in the DMI record.

(The actual length will be 6 bytes if adding a value for an 8-bit
field, which is certainly the most frequent use case. But if adding a
value for a 16-bit field for example, then the entry would be 7 byte
long.)

> + return;
> +
> + data = info->entries;
> +
> + for (i = 0; i < info->count; i++) {
> + u8 string_num = data[i * 5 + 4];
> + const char *string_ptr;
> + char *value;
> + int len;
> +
> + string_ptr = dmi_string_nosave(&info->header, string_num);
> + if (!string_ptr || !*string_ptr)
> + continue;
> +
> + len = strlen(string_ptr);
> + if (len == 0)
> + continue;
> +
> + value = dmi_alloc(len + 1);
> + if (!value)
> + continue;
> +
> + strscpy(value, string_ptr, len + 1);

Not sure why you allocate memory for the string, considering that
dmi_save_one_device() below does it too?

> +
> + dmi_save_one_device(DMI_DEV_TYPE_ADDITIONAL, value);
> + }
> +}

I'm not thrilled by the interface this offers. You end up arbitrarily
saving only one piece of information from the record (the free-form
string). You omit the reference handle (which isn't super-useful per
se, but could be used to find out the base DMI type, which would be
useful), nor the field offset within that DMI type, nor the new value
associated with that field.

This might be OK with your immediate use case, but lacks flexibility if
anyone else ever needs data from such a record.

Even for your use case, this seems pretty fragile. You end up
considering that any string starting with "AGESA" in a type 40 DMI
record is what you are looking for. While you don't have any guarantee
that the record in question relates to the CPU in general nor to one
specific type 4 record field. This could result in false positives.

> +
> static void __init dmi_save_extended_devices(const struct dmi_header *dm)
> {
> const char *name;
> @@ -526,8 +560,12 @@ static void __init dmi_decode(const struct dmi_header *dm, void *dummy)
> case DMI_ENTRY_IPMI_DEV:
> dmi_save_ipmi_device(dm);
> break;
> + case DMI_ENTRY_ADDITIONAL:
> + dmi_save_additional((const struct dmi_additional_info *)dm);
> + break;
> case DMI_ENTRY_ONBOARD_DEV_EXT:
> dmi_save_extended_devices(dm);
> + break;
> }
> }
>
> diff --git a/include/linux/dmi.h b/include/linux/dmi.h
> index a809b5095c259..3fc3d334b321d 100644
> --- a/include/linux/dmi.h
> +++ b/include/linux/dmi.h
> @@ -24,6 +24,7 @@ enum dmi_device_type {
> DMI_DEV_TYPE_OEM_STRING = -2,
> DMI_DEV_TYPE_DEV_ONBOARD = -3,
> DMI_DEV_TYPE_DEV_SLOT = -4,
> + DMI_DEV_TYPE_ADDITIONAL = -5,
> };
>
> enum dmi_entry_type {
> @@ -87,6 +88,12 @@ struct dmi_device {
> void *device_data; /* Type specific data */
> };
>
> +struct dmi_additional_info {
> + struct dmi_header header;
> + u8 count;
> + u8 entries[];
> +} __packed;
> +
> #ifdef CONFIG_DMI
>
> struct dmi_dev_onboard {

--
Jean Delvare
SUSE L3 Support