diff options
Diffstat (limited to 'drivers/firmware/dmi_scan.c')
| -rw-r--r-- | drivers/firmware/dmi_scan.c | 46 |
1 files changed, 31 insertions, 15 deletions
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 5066d1f1d687..70d39adf50dc 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -9,7 +9,7 @@ #include <linux/memblock.h> #include <linux/random.h> #include <asm/dmi.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #ifndef SMBIOS_ENTRY_POINT_SCAN_START #define SMBIOS_ENTRY_POINT_SCAN_START 0xF0000 @@ -21,7 +21,7 @@ EXPORT_SYMBOL_GPL(dmi_kobj); /* * DMI stands for "Desktop Management Interface". It is part * of and an antecedent to, SMBIOS, which stands for System - * Management BIOS. See further: http://www.dmtf.org/standards + * Management BIOS. See further: https://www.dmtf.org/standards */ static const char dmi_empty_string[] = ""; @@ -42,6 +42,7 @@ static struct dmi_memdev_info { u8 type; /* DDR2, DDR3, DDR4 etc */ } *dmi_memdev; static int dmi_memdev_nr; +static int dmi_memdev_populated_nr __initdata; static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) { @@ -102,6 +103,17 @@ static void dmi_decode_table(u8 *buf, const struct dmi_header *dm = (const struct dmi_header *)data; /* + * If a short entry is found (less than 4 bytes), not only it + * is invalid, but we cannot reliably locate the next entry. + */ + if (dm->length < sizeof(struct dmi_header)) { + pr_warn(FW_BUG + "Corrupted DMI table, offset %zd (only %d entries processed)\n", + data - buf, i); + break; + } + + /* * We want to know the total length (formatted area and * strings) before decoding to make sure we won't run off the * table in dmi_decode or dmi_string @@ -166,6 +178,7 @@ static int __init dmi_checksum(const u8 *buf, u8 len) static const char *dmi_ident[DMI_STRING_MAX]; static LIST_HEAD(dmi_devices); int dmi_available; +EXPORT_SYMBOL_GPL(dmi_available); /* * Save a DMI string @@ -447,6 +460,9 @@ static void __init save_mem_devices(const struct dmi_header *dm, void *v) else bytes = (u64)get_unaligned((u32 *)&d[0x1C]) << 20; + if (bytes) + dmi_memdev_populated_nr++; + dmi_memdev[nr].size = bytes; nr++; } @@ -566,8 +582,13 @@ static int __init dmi_present(const u8 *buf) { u32 smbios_ver; + /* + * The size of this structure is 31 bytes, but we also accept value + * 30 due to a mistake in SMBIOS specification version 2.1. + */ if (memcmp(buf, "_SM_", 4) == 0 && - buf[5] < 32 && dmi_checksum(buf, buf[5])) { + buf[5] >= 30 && buf[5] <= 32 && + dmi_checksum(buf, buf[5])) { smbios_ver = get_unaligned_be16(buf + 6); smbios_entry_point_size = buf[5]; memcpy(smbios_entry_point, buf, smbios_entry_point_size); @@ -628,8 +649,9 @@ static int __init dmi_present(const u8 *buf) static int __init dmi_smbios3_present(const u8 *buf) { if (memcmp(buf, "_SM3_", 5) == 0 && - buf[6] < 32 && dmi_checksum(buf, buf[6])) { - dmi_ver = get_unaligned_be32(buf + 6) & 0xFFFFFF; + buf[6] >= 24 && buf[6] <= 32 && + dmi_checksum(buf, buf[6])) { + dmi_ver = get_unaligned_be24(buf + 7); dmi_num = 0; /* No longer specified */ dmi_len = get_unaligned_le32(buf + 12); dmi_base = get_unaligned_le64(buf + 16); @@ -739,16 +761,8 @@ static void __init dmi_scan_machine(void) pr_info("DMI not present or invalid.\n"); } -static ssize_t raw_table_read(struct file *file, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t pos, size_t count) -{ - memcpy(buf, attr->private + pos, count); - return count; -} - -static BIN_ATTR(smbios_entry_point, S_IRUSR, raw_table_read, NULL, 0); -static BIN_ATTR(DMI, S_IRUSR, raw_table_read, NULL, 0); +static __ro_after_init BIN_ATTR_SIMPLE_ADMIN_RO(smbios_entry_point); +static __ro_after_init BIN_ATTR_SIMPLE_ADMIN_RO(DMI); static int __init dmi_init(void) { @@ -817,6 +831,8 @@ void __init dmi_setup(void) return; dmi_memdev_walk(); + pr_info("DMI: Memory slots populated: %d/%d\n", + dmi_memdev_populated_nr, dmi_memdev_nr); dump_stack_set_arch_desc("%s", dmi_ids_string); } |
