Message ID | 1444316696-946-2-git-send-email-colin.king@canonical.com |
---|---|
State | Accepted |
Headers | show |
On 2015年10月08日 23:04, Colin King wrote: > From: Jiri Vohanka <jvohanka@redhat.com> > > fix two issues in the 'dmicheck' test: > > 1) If 'SMBIOS' tables are not found in 'dmicheck_test2' then the > tests for SMBIOS 3.0 tables are skipped as well. But the > SMBIOS reference specification (version 3.0.0) says in > section 5 (Accessing SMBIOS information): > 'An implementation may provide either the 32-bit entry > point or the 64-bit entry point, or both.'. > This bug affected aarch64 systems I worked with since the 32-bit > tables were not provided. > > 2) As of commit https://git.kernel.org/cgit/linux/kernel/git/arm64/ > linux.git/commit/?id=d7f96f97c4031fa4ffdb7801f9aae23e96170a6f, > the SMBIOS tables are accessible in > /sys/firmware/dmi/tables/smbios_entry_point and > /sys/firmware/dmi/tables/DMI. This bug affected aarch64 systems > I worked with since the access to SMBIOS tables via /dev/mem > was not allowed if kernel was compiled with 'CONFIG_STRICT_DEVMEM=y'. > > The attached patch includes the following changes: > > - The test 'dmicheck_test2' is split into 'dmicheck_test2' and > 'dmicheck_test3', the first one checking SMBIOS table and the > second one checking SMBIOS 3.0 table. Thus, if one of the > SMBIOS tables is missing then only one of the tests is skipped. > > - If the access to SMBIOS tables via /dev/mem fails on UEFI systems > then the tables are loaded from /sys/firmware/dmi/tables/. > If /sys/firmware/dmi/tables/smbios_entry_point begins with '_SM_' > then the tables from /sys/firmware/dmi/tables/ are used as SMBIOS > tables. > If /sys/firmware/dmi/tables/smbios_entry_point begins with '_SM3_' > then the tables from /sys/firmware/dmi/tables/ are used as SMBIOS > 3.0 tables. This change allows access to SMBIOS tables without > using /dev/mem on UEFI systems. (The address of SMBIOS entry point > structure can be taken form /sys/firmware/efi/systab and the SMBIOS > tables can be read from /sys/firmware/dmi/tables/.) > > I tested the patch on: > - aarch64 system (with UEFI) - with 4.2.0 kernel > - x86_64 system without UEFI with access to /dev/mem - > Fedora23 with kernel-4.2.2-300.fc23.x86_64 > - x86_64 system with UEFI without acess to /dev/mem - > Fedora23 with kernel-4.2.2-300.fc23.x86_64 > - x86 system without UEFI with access to /dev/mem - > Fedora23 with kernel-4.2.2-300.fc23.i686+PAE > > [ with minor commit message edits and some whitespace clean up by > Colin Ian King ] > > Signed-off-by: Jiri Vohanka <jvohanka@redhat.com> > Tested-by: Colin Ian King <colin.king@canonical.com> > Signed-off-by: Colin Ian King <colin.king@canonical.com> > --- > src/dmi/dmicheck/dmicheck.c | 156 ++++++++++++++++++++++++++++++++------------ > src/lib/src/fwts_smbios.c | 66 +++++++++++++++---- > 2 files changed, 166 insertions(+), 56 deletions(-) > > diff --git a/src/dmi/dmicheck/dmicheck.c b/src/dmi/dmicheck/dmicheck.c > index d0dc183..eeb227a 100644 > --- a/src/dmi/dmicheck/dmicheck.c > +++ b/src/dmi/dmicheck/dmicheck.c > @@ -33,6 +33,7 @@ > #include <sys/stat.h> > #include <unistd.h> > #include <limits.h> > +#include <fcntl.h> > > #define DMI_VERSION (0x0300) > #define VERSION_MAJOR(v) ((v) >> 8) > @@ -309,6 +310,94 @@ static fwts_dmi_used_by_kernel dmi_used_by_kernel_table[] = { > { TYPE_EOD, 0xff }, > }; > > +static int dmi_load_file(const char* filename, void *buf, size_t size) > +{ > + int fd; > + ssize_t ret; > + > + if ((fd = open(filename, O_RDONLY)) < 0) > + return FWTS_ERROR; > + ret = read(fd, buf, size); > + close(fd); > + if (ret != (ssize_t)size) > + return FWTS_ERROR; > + return FWTS_OK; > +} > + > +static void* dmi_table_smbios(fwts_framework *fw, fwts_smbios_entry *entry) > +{ > + off_t addr = (off_t)entry->struct_table_address; > + size_t length = (size_t)entry->struct_table_length; > + void *table; > + void *mem; > + char anchor[8]; > + > + mem = fwts_mmap(addr, length); > + if (mem != FWTS_MAP_FAILED) { > + table = malloc(length); > + if (table) > + memcpy(table, mem, length); > + (void)fwts_munmap(mem, length); > + return table; > + } > + > + if (dmi_load_file("/sys/firmware/dmi/tables/smbios_entry_point", anchor, 4) == FWTS_OK > + && strncmp(anchor, "_SM_", 4) == 0) { > + table = malloc(length); > + if (!table) > + return NULL; > + if (dmi_load_file("/sys/firmware/dmi/tables/DMI", table, length) == FWTS_OK) { > + fwts_log_info(fw, "SMBIOS table loaded from /sys/firmware/dmi/tables/DMI\n"); > + return table; > + } > + free(table); > + } > + > + fwts_log_error(fw, "Cannot mmap SMBIOS table from %8.8" PRIx32 "..%8.8" PRIx32 ".", > + entry->struct_table_address, entry->struct_table_address + entry->struct_table_length); > + return NULL; > +} > + > +static void* dmi_table_smbios30(fwts_framework *fw, fwts_smbios30_entry *entry) > +{ > + off_t addr = (off_t)entry->struct_table_address; > + size_t length = (size_t)entry->struct_table_max_size; > + void *table; > + void *mem; > + char anchor[8]; > + > + mem = fwts_mmap(addr, length); > + if (mem != FWTS_MAP_FAILED) { > + table = malloc(length); > + if (table) > + memcpy(table, mem, length); > + (void)fwts_munmap(mem, length); > + return table; > + } > + > + if (dmi_load_file("/sys/firmware/dmi/tables/smbios_entry_point", anchor, 5) == FWTS_OK > + && strncmp(anchor, "_SM3_", 5) == 0) { > + table = malloc(length); > + if (!table) > + return NULL; > + if (dmi_load_file("/sys/firmware/dmi/tables/DMI", table, length) == FWTS_OK) { > + fwts_log_info(fw, "SMBIOS30 table loaded from /sys/firmware/dmi/tables/DMI\n"); > + return table; > + } > + free(table); > + } > + > + fwts_log_error(fw, "Cannot mmap SMBIOS 3.0 table from %16.16" PRIx64 "..%16.16" PRIx64 ".", > + entry->struct_table_address, entry->struct_table_address + entry->struct_table_max_size); > + return NULL; > +} > + > +static void dmi_table_free(void* table) > +{ > + if (table) > + free(table); > +} > + > static void dmi_dump_entry(fwts_framework *fw, fwts_smbios_entry *entry, fwts_smbios_type type) > { > if (type == FWTS_SMBIOS) { > @@ -365,17 +454,9 @@ static int dmi_sane(fwts_framework *fw, fwts_smbios_entry *entry) > uint16_t table_length = entry->struct_table_length; > int ret = FWTS_OK; > > - ptr = table = fwts_mmap((off_t)entry->struct_table_address, > - (size_t)table_length); > - if (table == FWTS_MAP_FAILED) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, > - "SMBIOSTableAddressNotMapped", > - "Cannot mmap SMBIOS tables from " > - "%8.8" PRIx32 "..%8.8" PRIx32 ".", > - entry->struct_table_address, > - entry->struct_table_address + table_length); > - return FWTS_ERROR; > - } > + ptr = table = dmi_table_smbios(fw, entry); > + if (table == NULL) > + return FWTS_ERROR; > > for (i = 0; i < entry->number_smbios_structures; i++) { > if (ptr > table + table_length) { > @@ -422,7 +503,7 @@ static int dmi_sane(fwts_framework *fw, fwts_smbios_entry *entry) > ret = FWTS_ERROR; > } > > - (void)fwts_munmap(table, (size_t)entry->struct_table_length); > + dmi_table_free(table); > > return ret; > } > @@ -520,17 +601,9 @@ static int dmi_smbios30_sane(fwts_framework *fw, fwts_smbios30_entry *entry) > uint32_t table_length = entry->struct_table_max_size; > int ret = FWTS_OK; > > - ptr = table = fwts_mmap((off_t)entry->struct_table_address, > - (size_t)table_length); > - if (table == FWTS_MAP_FAILED) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, > - "SMBIOS30TableAddressNotMapped", > - "Cannot mmap SMBIOS 3.0 tables from " > - "%16.16" PRIx64 "..%16.16" PRIx64 ".", > - entry->struct_table_address, > - entry->struct_table_address + table_length); > - return FWTS_ERROR; > - } > + ptr = table = dmi_table_smbios30(fw, entry); > + if (table == NULL) > + return FWTS_ERROR; > > while (1) > { > @@ -579,7 +652,7 @@ static int dmi_smbios30_sane(fwts_framework *fw, fwts_smbios30_entry *entry) > } > } > > - (void)fwts_munmap(table, (size_t)entry->struct_table_max_size); > + dmi_table_free(table); > > return ret; > } > @@ -1796,7 +1869,6 @@ static int dmicheck_test2(fwts_framework *fw) > { > void *addr; > fwts_smbios_entry entry; > - fwts_smbios30_entry entry30; > fwts_smbios_type type; > uint16_t version = 0; > uint8_t *table; > @@ -1823,20 +1895,23 @@ static int dmicheck_test2(fwts_framework *fw) > if (dmi_version_check(fw, version) != FWTS_OK) > return FWTS_SKIP; > > - table = fwts_mmap((off_t)entry.struct_table_address, > - (size_t)entry.struct_table_length); > - if (table == FWTS_MAP_FAILED) { > - fwts_log_error(fw, "Cannot mmap SMBIOS tables from " > - "%8.8" PRIx32 "..%8.8" PRIx32 ".", > - entry.struct_table_address, > - entry.struct_table_address + entry.struct_table_length); > + table = dmi_table_smbios(fw, &entry); > + if (table == NULL) > return FWTS_ERROR; > - } > > dmi_scan_tables(fw, &entry, table); > > - (void)fwts_munmap(table, (size_t)entry.struct_table_length); > + dmi_table_free(table); > > + return FWTS_OK; > +} > + > +static int dmicheck_test3(fwts_framework *fw) > +{ > + void *addr; > + fwts_smbios30_entry entry30; > + uint16_t version = 0; > + uint8_t *table; > > if (!smbios30_found) { > fwts_skipped(fw, "Cannot find SMBIOS30 table entry, skip the test."); > @@ -1850,19 +1925,13 @@ static int dmicheck_test2(fwts_framework *fw) > return FWTS_ERROR; > } > > - table = fwts_mmap((off_t)entry30.struct_table_address, > - (size_t)entry30.struct_table_max_size); > - if (table == FWTS_MAP_FAILED) { > - fwts_log_error(fw, "Cannot mmap SMBIOS 3.0 table from " > - "%16.16" PRIx64 "..%16.16" PRIx64 ".", > - entry30.struct_table_address, > - entry30.struct_table_address + entry30.struct_table_max_size); > + table = dmi_table_smbios30(fw, &entry30); > + if (table == NULL) > return FWTS_ERROR; > - } > > dmi_scan_smbios30_table(fw, &entry30, table); > > - (void)fwts_munmap(table, (size_t)entry30.struct_table_max_size); > + dmi_table_free(table); > > return FWTS_OK; > } > @@ -1870,6 +1939,7 @@ static int dmicheck_test2(fwts_framework *fw) > static fwts_framework_minor_test dmicheck_tests[] = { > { dmicheck_test1, "Find and test SMBIOS Table Entry Points." }, > { dmicheck_test2, "Test DMI/SMBIOS tables for errors." }, > + { dmicheck_test3, "Test DMI/SMBIOS3 tables for errors." }, > { NULL, NULL } > }; > > diff --git a/src/lib/src/fwts_smbios.c b/src/lib/src/fwts_smbios.c > index 8b0d975..4cafb81 100644 > --- a/src/lib/src/fwts_smbios.c > +++ b/src/lib/src/fwts_smbios.c > @@ -17,9 +17,32 @@ > * > */ > > +#include <sys/types.h> > +#include <sys/stat.h> > +#include <fcntl.h> > +#include <unistd.h> > #include "fwts.h" > > #if defined(FWTS_ARCH_INTEL) || defined(FWTS_ARCH_AARCH64) > + > +/* > + * fwts_load_file() > + * loads file to memory > + */ > +static int fwts_load_file(const char* filename, void *buf, size_t size) > +{ > + int fd; > + ssize_t ret; > + > + if ((fd = open(filename, O_RDONLY)) < 0) > + return FWTS_ERROR; > + ret = read(fd, buf, size); > + close(fd); > + if (ret != (ssize_t)size) > + return FWTS_ERROR; > + return FWTS_OK; > +} > + > /* > * fwts_smbios_find_entry_uefi() > * find SMBIOS structure table entry from UEFI systab > @@ -30,15 +53,24 @@ static void *fwts_smbios_find_entry_uefi(fwts_framework *fw, fwts_smbios_entry * > fwts_smbios_entry *mapped_entry; > > if ((addr = fwts_scan_efi_systab("SMBIOS")) != NULL) { > - if ((mapped_entry = fwts_mmap((off_t)addr, sizeof(fwts_smbios_entry))) == FWTS_MAP_FAILED) { > - fwts_log_error(fw, "Cannot mmap SMBIOS entry at %p\n", addr); > - return NULL; > + > + if ((mapped_entry = fwts_mmap((off_t)addr, sizeof(fwts_smbios_entry))) != FWTS_MAP_FAILED) { > + *entry = *mapped_entry; > + (void)fwts_munmap(mapped_entry, sizeof(fwts_smbios_entry)); > + *type = FWTS_SMBIOS; > + return addr; > } > - *entry = *mapped_entry; > - *type = FWTS_SMBIOS; > - (void)fwts_munmap(mapped_entry, sizeof(fwts_smbios_entry)); > + > + if (fwts_load_file("/sys/firmware/dmi/tables/smbios_entry_point", > + entry, sizeof(fwts_smbios_entry)) == FWTS_OK && !strncmp((char*)entry, "_SM_", 4)) { > + fwts_log_info(fw, "SMBIOS entry loaded from /sys/firmware/dmi/tables/smbios_entry_point\n"); > + *type = FWTS_SMBIOS; > + return addr; > + } > + > + fwts_log_error(fw, "Cannot mmap SMBIOS entry at %p\n", addr); > } > - return addr; > + return NULL; > } > > /* > @@ -51,14 +83,22 @@ static void *fwts_smbios30_find_entry_uefi(fwts_framework *fw, fwts_smbios30_ent > fwts_smbios30_entry *mapped_entry; > > if ((addr = fwts_scan_efi_systab("SMBIOS3")) != NULL) { > - if ((mapped_entry = fwts_mmap((off_t)addr, sizeof(fwts_smbios30_entry))) == FWTS_MAP_FAILED) { > - fwts_log_error(fw, "Cannot mmap SMBIOS30 entry at %p\n", addr); > - return NULL; > + > + if ((mapped_entry = fwts_mmap((off_t)addr, sizeof(fwts_smbios30_entry))) != FWTS_MAP_FAILED) { > + *entry = *mapped_entry; > + (void)fwts_munmap(mapped_entry, sizeof(fwts_smbios30_entry)); > + return addr; > } > - *entry = *mapped_entry; > - (void)fwts_munmap(mapped_entry, sizeof(fwts_smbios30_entry)); > + > + if (fwts_load_file("/sys/firmware/dmi/tables/smbios_entry_point", > + entry, sizeof(fwts_smbios30_entry)) == FWTS_OK && !strncmp((char*)entry, "_SM3_", 5)) { > + fwts_log_info(fw, "SMBIOS30 entry loaded from /sys/firmware/dmi/tables/smbios_entry_point\n"); > + return addr; > + } > + > + fwts_log_error(fw, "Cannot mmap SMBIOS30 entry at %p\n", addr); > } > - return addr; > + return NULL; > } > > #if defined(FWTS_ARCH_INTEL) > Acked-by: Ivan Hu <ivan.hu@canonical.com>
On 10/08/2015 11:04 PM, Colin King wrote: > From: Jiri Vohanka <jvohanka@redhat.com> > > fix two issues in the 'dmicheck' test: > > 1) If 'SMBIOS' tables are not found in 'dmicheck_test2' then the > tests for SMBIOS 3.0 tables are skipped as well. But the > SMBIOS reference specification (version 3.0.0) says in > section 5 (Accessing SMBIOS information): > 'An implementation may provide either the 32-bit entry > point or the 64-bit entry point, or both.'. > This bug affected aarch64 systems I worked with since the 32-bit > tables were not provided. > > 2) As of commit https://git.kernel.org/cgit/linux/kernel/git/arm64/ > linux.git/commit/?id=d7f96f97c4031fa4ffdb7801f9aae23e96170a6f, > the SMBIOS tables are accessible in > /sys/firmware/dmi/tables/smbios_entry_point and > /sys/firmware/dmi/tables/DMI. This bug affected aarch64 systems > I worked with since the access to SMBIOS tables via /dev/mem > was not allowed if kernel was compiled with 'CONFIG_STRICT_DEVMEM=y'. > > The attached patch includes the following changes: > > - The test 'dmicheck_test2' is split into 'dmicheck_test2' and > 'dmicheck_test3', the first one checking SMBIOS table and the > second one checking SMBIOS 3.0 table. Thus, if one of the > SMBIOS tables is missing then only one of the tests is skipped. > > - If the access to SMBIOS tables via /dev/mem fails on UEFI systems > then the tables are loaded from /sys/firmware/dmi/tables/. > If /sys/firmware/dmi/tables/smbios_entry_point begins with '_SM_' > then the tables from /sys/firmware/dmi/tables/ are used as SMBIOS > tables. > If /sys/firmware/dmi/tables/smbios_entry_point begins with '_SM3_' > then the tables from /sys/firmware/dmi/tables/ are used as SMBIOS > 3.0 tables. This change allows access to SMBIOS tables without > using /dev/mem on UEFI systems. (The address of SMBIOS entry point > structure can be taken form /sys/firmware/efi/systab and the SMBIOS > tables can be read from /sys/firmware/dmi/tables/.) > > I tested the patch on: > - aarch64 system (with UEFI) - with 4.2.0 kernel > - x86_64 system without UEFI with access to /dev/mem - > Fedora23 with kernel-4.2.2-300.fc23.x86_64 > - x86_64 system with UEFI without acess to /dev/mem - > Fedora23 with kernel-4.2.2-300.fc23.x86_64 > - x86 system without UEFI with access to /dev/mem - > Fedora23 with kernel-4.2.2-300.fc23.i686+PAE > > [ with minor commit message edits and some whitespace clean up by > Colin Ian King ] > > Signed-off-by: Jiri Vohanka <jvohanka@redhat.com> > Tested-by: Colin Ian King <colin.king@canonical.com> > Signed-off-by: Colin Ian King <colin.king@canonical.com> > --- > src/dmi/dmicheck/dmicheck.c | 156 ++++++++++++++++++++++++++++++++------------ > src/lib/src/fwts_smbios.c | 66 +++++++++++++++---- > 2 files changed, 166 insertions(+), 56 deletions(-) > > diff --git a/src/dmi/dmicheck/dmicheck.c b/src/dmi/dmicheck/dmicheck.c > index d0dc183..eeb227a 100644 > --- a/src/dmi/dmicheck/dmicheck.c > +++ b/src/dmi/dmicheck/dmicheck.c > @@ -33,6 +33,7 @@ > #include <sys/stat.h> > #include <unistd.h> > #include <limits.h> > +#include <fcntl.h> > > #define DMI_VERSION (0x0300) > #define VERSION_MAJOR(v) ((v) >> 8) > @@ -309,6 +310,94 @@ static fwts_dmi_used_by_kernel dmi_used_by_kernel_table[] = { > { TYPE_EOD, 0xff }, > }; > > +static int dmi_load_file(const char* filename, void *buf, size_t size) > +{ > + int fd; > + ssize_t ret; > + > + if ((fd = open(filename, O_RDONLY)) < 0) > + return FWTS_ERROR; > + ret = read(fd, buf, size); > + close(fd); > + if (ret != (ssize_t)size) > + return FWTS_ERROR; > + return FWTS_OK; > +} > + > +static void* dmi_table_smbios(fwts_framework *fw, fwts_smbios_entry *entry) > +{ > + off_t addr = (off_t)entry->struct_table_address; > + size_t length = (size_t)entry->struct_table_length; > + void *table; > + void *mem; > + char anchor[8]; > + > + mem = fwts_mmap(addr, length); > + if (mem != FWTS_MAP_FAILED) { > + table = malloc(length); > + if (table) > + memcpy(table, mem, length); > + (void)fwts_munmap(mem, length); > + return table; > + } > + > + if (dmi_load_file("/sys/firmware/dmi/tables/smbios_entry_point", anchor, 4) == FWTS_OK > + && strncmp(anchor, "_SM_", 4) == 0) { > + table = malloc(length); > + if (!table) > + return NULL; > + if (dmi_load_file("/sys/firmware/dmi/tables/DMI", table, length) == FWTS_OK) { > + fwts_log_info(fw, "SMBIOS table loaded from /sys/firmware/dmi/tables/DMI\n"); > + return table; > + } > + free(table); > + } > + > + fwts_log_error(fw, "Cannot mmap SMBIOS table from %8.8" PRIx32 "..%8.8" PRIx32 ".", > + entry->struct_table_address, entry->struct_table_address + entry->struct_table_length); > + return NULL; > +} > + > +static void* dmi_table_smbios30(fwts_framework *fw, fwts_smbios30_entry *entry) > +{ > + off_t addr = (off_t)entry->struct_table_address; > + size_t length = (size_t)entry->struct_table_max_size; > + void *table; > + void *mem; > + char anchor[8]; > + > + mem = fwts_mmap(addr, length); > + if (mem != FWTS_MAP_FAILED) { > + table = malloc(length); > + if (table) > + memcpy(table, mem, length); > + (void)fwts_munmap(mem, length); > + return table; > + } > + > + if (dmi_load_file("/sys/firmware/dmi/tables/smbios_entry_point", anchor, 5) == FWTS_OK > + && strncmp(anchor, "_SM3_", 5) == 0) { > + table = malloc(length); > + if (!table) > + return NULL; > + if (dmi_load_file("/sys/firmware/dmi/tables/DMI", table, length) == FWTS_OK) { > + fwts_log_info(fw, "SMBIOS30 table loaded from /sys/firmware/dmi/tables/DMI\n"); > + return table; > + } > + free(table); > + } > + > + fwts_log_error(fw, "Cannot mmap SMBIOS 3.0 table from %16.16" PRIx64 "..%16.16" PRIx64 ".", > + entry->struct_table_address, entry->struct_table_address + entry->struct_table_max_size); > + return NULL; > +} > + > +static void dmi_table_free(void* table) > +{ > + if (table) > + free(table); > +} > + > static void dmi_dump_entry(fwts_framework *fw, fwts_smbios_entry *entry, fwts_smbios_type type) > { > if (type == FWTS_SMBIOS) { > @@ -365,17 +454,9 @@ static int dmi_sane(fwts_framework *fw, fwts_smbios_entry *entry) > uint16_t table_length = entry->struct_table_length; > int ret = FWTS_OK; > > - ptr = table = fwts_mmap((off_t)entry->struct_table_address, > - (size_t)table_length); > - if (table == FWTS_MAP_FAILED) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, > - "SMBIOSTableAddressNotMapped", > - "Cannot mmap SMBIOS tables from " > - "%8.8" PRIx32 "..%8.8" PRIx32 ".", > - entry->struct_table_address, > - entry->struct_table_address + table_length); > - return FWTS_ERROR; > - } > + ptr = table = dmi_table_smbios(fw, entry); > + if (table == NULL) > + return FWTS_ERROR; > > for (i = 0; i < entry->number_smbios_structures; i++) { > if (ptr > table + table_length) { > @@ -422,7 +503,7 @@ static int dmi_sane(fwts_framework *fw, fwts_smbios_entry *entry) > ret = FWTS_ERROR; > } > > - (void)fwts_munmap(table, (size_t)entry->struct_table_length); > + dmi_table_free(table); > > return ret; > } > @@ -520,17 +601,9 @@ static int dmi_smbios30_sane(fwts_framework *fw, fwts_smbios30_entry *entry) > uint32_t table_length = entry->struct_table_max_size; > int ret = FWTS_OK; > > - ptr = table = fwts_mmap((off_t)entry->struct_table_address, > - (size_t)table_length); > - if (table == FWTS_MAP_FAILED) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, > - "SMBIOS30TableAddressNotMapped", > - "Cannot mmap SMBIOS 3.0 tables from " > - "%16.16" PRIx64 "..%16.16" PRIx64 ".", > - entry->struct_table_address, > - entry->struct_table_address + table_length); > - return FWTS_ERROR; > - } > + ptr = table = dmi_table_smbios30(fw, entry); > + if (table == NULL) > + return FWTS_ERROR; > > while (1) > { > @@ -579,7 +652,7 @@ static int dmi_smbios30_sane(fwts_framework *fw, fwts_smbios30_entry *entry) > } > } > > - (void)fwts_munmap(table, (size_t)entry->struct_table_max_size); > + dmi_table_free(table); > > return ret; > } > @@ -1796,7 +1869,6 @@ static int dmicheck_test2(fwts_framework *fw) > { > void *addr; > fwts_smbios_entry entry; > - fwts_smbios30_entry entry30; > fwts_smbios_type type; > uint16_t version = 0; > uint8_t *table; > @@ -1823,20 +1895,23 @@ static int dmicheck_test2(fwts_framework *fw) > if (dmi_version_check(fw, version) != FWTS_OK) > return FWTS_SKIP; > > - table = fwts_mmap((off_t)entry.struct_table_address, > - (size_t)entry.struct_table_length); > - if (table == FWTS_MAP_FAILED) { > - fwts_log_error(fw, "Cannot mmap SMBIOS tables from " > - "%8.8" PRIx32 "..%8.8" PRIx32 ".", > - entry.struct_table_address, > - entry.struct_table_address + entry.struct_table_length); > + table = dmi_table_smbios(fw, &entry); > + if (table == NULL) > return FWTS_ERROR; > - } > > dmi_scan_tables(fw, &entry, table); > > - (void)fwts_munmap(table, (size_t)entry.struct_table_length); > + dmi_table_free(table); > > + return FWTS_OK; > +} > + > +static int dmicheck_test3(fwts_framework *fw) > +{ > + void *addr; > + fwts_smbios30_entry entry30; > + uint16_t version = 0; > + uint8_t *table; > > if (!smbios30_found) { > fwts_skipped(fw, "Cannot find SMBIOS30 table entry, skip the test."); > @@ -1850,19 +1925,13 @@ static int dmicheck_test2(fwts_framework *fw) > return FWTS_ERROR; > } > > - table = fwts_mmap((off_t)entry30.struct_table_address, > - (size_t)entry30.struct_table_max_size); > - if (table == FWTS_MAP_FAILED) { > - fwts_log_error(fw, "Cannot mmap SMBIOS 3.0 table from " > - "%16.16" PRIx64 "..%16.16" PRIx64 ".", > - entry30.struct_table_address, > - entry30.struct_table_address + entry30.struct_table_max_size); > + table = dmi_table_smbios30(fw, &entry30); > + if (table == NULL) > return FWTS_ERROR; > - } > > dmi_scan_smbios30_table(fw, &entry30, table); > > - (void)fwts_munmap(table, (size_t)entry30.struct_table_max_size); > + dmi_table_free(table); > > return FWTS_OK; > } > @@ -1870,6 +1939,7 @@ static int dmicheck_test2(fwts_framework *fw) > static fwts_framework_minor_test dmicheck_tests[] = { > { dmicheck_test1, "Find and test SMBIOS Table Entry Points." }, > { dmicheck_test2, "Test DMI/SMBIOS tables for errors." }, > + { dmicheck_test3, "Test DMI/SMBIOS3 tables for errors." }, > { NULL, NULL } > }; > > diff --git a/src/lib/src/fwts_smbios.c b/src/lib/src/fwts_smbios.c > index 8b0d975..4cafb81 100644 > --- a/src/lib/src/fwts_smbios.c > +++ b/src/lib/src/fwts_smbios.c > @@ -17,9 +17,32 @@ > * > */ > > +#include <sys/types.h> > +#include <sys/stat.h> > +#include <fcntl.h> > +#include <unistd.h> > #include "fwts.h" > > #if defined(FWTS_ARCH_INTEL) || defined(FWTS_ARCH_AARCH64) > + > +/* > + * fwts_load_file() > + * loads file to memory > + */ > +static int fwts_load_file(const char* filename, void *buf, size_t size) > +{ > + int fd; > + ssize_t ret; > + > + if ((fd = open(filename, O_RDONLY)) < 0) > + return FWTS_ERROR; > + ret = read(fd, buf, size); > + close(fd); > + if (ret != (ssize_t)size) > + return FWTS_ERROR; > + return FWTS_OK; > +} > + > /* > * fwts_smbios_find_entry_uefi() > * find SMBIOS structure table entry from UEFI systab > @@ -30,15 +53,24 @@ static void *fwts_smbios_find_entry_uefi(fwts_framework *fw, fwts_smbios_entry * > fwts_smbios_entry *mapped_entry; > > if ((addr = fwts_scan_efi_systab("SMBIOS")) != NULL) { > - if ((mapped_entry = fwts_mmap((off_t)addr, sizeof(fwts_smbios_entry))) == FWTS_MAP_FAILED) { > - fwts_log_error(fw, "Cannot mmap SMBIOS entry at %p\n", addr); > - return NULL; > + > + if ((mapped_entry = fwts_mmap((off_t)addr, sizeof(fwts_smbios_entry))) != FWTS_MAP_FAILED) { > + *entry = *mapped_entry; > + (void)fwts_munmap(mapped_entry, sizeof(fwts_smbios_entry)); > + *type = FWTS_SMBIOS; > + return addr; > } > - *entry = *mapped_entry; > - *type = FWTS_SMBIOS; > - (void)fwts_munmap(mapped_entry, sizeof(fwts_smbios_entry)); > + > + if (fwts_load_file("/sys/firmware/dmi/tables/smbios_entry_point", > + entry, sizeof(fwts_smbios_entry)) == FWTS_OK && !strncmp((char*)entry, "_SM_", 4)) { > + fwts_log_info(fw, "SMBIOS entry loaded from /sys/firmware/dmi/tables/smbios_entry_point\n"); > + *type = FWTS_SMBIOS; > + return addr; > + } > + > + fwts_log_error(fw, "Cannot mmap SMBIOS entry at %p\n", addr); > } > - return addr; > + return NULL; > } > > /* > @@ -51,14 +83,22 @@ static void *fwts_smbios30_find_entry_uefi(fwts_framework *fw, fwts_smbios30_ent > fwts_smbios30_entry *mapped_entry; > > if ((addr = fwts_scan_efi_systab("SMBIOS3")) != NULL) { > - if ((mapped_entry = fwts_mmap((off_t)addr, sizeof(fwts_smbios30_entry))) == FWTS_MAP_FAILED) { > - fwts_log_error(fw, "Cannot mmap SMBIOS30 entry at %p\n", addr); > - return NULL; > + > + if ((mapped_entry = fwts_mmap((off_t)addr, sizeof(fwts_smbios30_entry))) != FWTS_MAP_FAILED) { > + *entry = *mapped_entry; > + (void)fwts_munmap(mapped_entry, sizeof(fwts_smbios30_entry)); > + return addr; > } > - *entry = *mapped_entry; > - (void)fwts_munmap(mapped_entry, sizeof(fwts_smbios30_entry)); > + > + if (fwts_load_file("/sys/firmware/dmi/tables/smbios_entry_point", > + entry, sizeof(fwts_smbios30_entry)) == FWTS_OK && !strncmp((char*)entry, "_SM3_", 5)) { > + fwts_log_info(fw, "SMBIOS30 entry loaded from /sys/firmware/dmi/tables/smbios_entry_point\n"); > + return addr; > + } > + > + fwts_log_error(fw, "Cannot mmap SMBIOS30 entry at %p\n", addr); > } > - return addr; > + return NULL; > } > > #if defined(FWTS_ARCH_INTEL) > Acked-by: Alex Hung <alex.hung@canonical.com>
diff --git a/src/dmi/dmicheck/dmicheck.c b/src/dmi/dmicheck/dmicheck.c index d0dc183..eeb227a 100644 --- a/src/dmi/dmicheck/dmicheck.c +++ b/src/dmi/dmicheck/dmicheck.c @@ -33,6 +33,7 @@ #include <sys/stat.h> #include <unistd.h> #include <limits.h> +#include <fcntl.h> #define DMI_VERSION (0x0300) #define VERSION_MAJOR(v) ((v) >> 8) @@ -309,6 +310,94 @@ static fwts_dmi_used_by_kernel dmi_used_by_kernel_table[] = { { TYPE_EOD, 0xff }, }; +static int dmi_load_file(const char* filename, void *buf, size_t size) +{ + int fd; + ssize_t ret; + + if ((fd = open(filename, O_RDONLY)) < 0) + return FWTS_ERROR; + ret = read(fd, buf, size); + close(fd); + if (ret != (ssize_t)size) + return FWTS_ERROR; + return FWTS_OK; +} + +static void* dmi_table_smbios(fwts_framework *fw, fwts_smbios_entry *entry) +{ + off_t addr = (off_t)entry->struct_table_address; + size_t length = (size_t)entry->struct_table_length; + void *table; + void *mem; + char anchor[8]; + + mem = fwts_mmap(addr, length); + if (mem != FWTS_MAP_FAILED) { + table = malloc(length); + if (table) + memcpy(table, mem, length); + (void)fwts_munmap(mem, length); + return table; + } + + if (dmi_load_file("/sys/firmware/dmi/tables/smbios_entry_point", anchor, 4) == FWTS_OK + && strncmp(anchor, "_SM_", 4) == 0) { + table = malloc(length); + if (!table) + return NULL; + if (dmi_load_file("/sys/firmware/dmi/tables/DMI", table, length) == FWTS_OK) { + fwts_log_info(fw, "SMBIOS table loaded from /sys/firmware/dmi/tables/DMI\n"); + return table; + } + free(table); + } + + fwts_log_error(fw, "Cannot mmap SMBIOS table from %8.8" PRIx32 "..%8.8" PRIx32 ".", + entry->struct_table_address, entry->struct_table_address + entry->struct_table_length); + return NULL; +} + +static void* dmi_table_smbios30(fwts_framework *fw, fwts_smbios30_entry *entry) +{ + off_t addr = (off_t)entry->struct_table_address; + size_t length = (size_t)entry->struct_table_max_size; + void *table; + void *mem; + char anchor[8]; + + mem = fwts_mmap(addr, length); + if (mem != FWTS_MAP_FAILED) { + table = malloc(length); + if (table) + memcpy(table, mem, length); + (void)fwts_munmap(mem, length); + return table; + } + + if (dmi_load_file("/sys/firmware/dmi/tables/smbios_entry_point", anchor, 5) == FWTS_OK + && strncmp(anchor, "_SM3_", 5) == 0) { + table = malloc(length); + if (!table) + return NULL; + if (dmi_load_file("/sys/firmware/dmi/tables/DMI", table, length) == FWTS_OK) { + fwts_log_info(fw, "SMBIOS30 table loaded from /sys/firmware/dmi/tables/DMI\n"); + return table; + } + free(table); + } + + fwts_log_error(fw, "Cannot mmap SMBIOS 3.0 table from %16.16" PRIx64 "..%16.16" PRIx64 ".", + entry->struct_table_address, entry->struct_table_address + entry->struct_table_max_size); + return NULL; +} + +static void dmi_table_free(void* table) +{ + if (table) + free(table); +} + static void dmi_dump_entry(fwts_framework *fw, fwts_smbios_entry *entry, fwts_smbios_type type) { if (type == FWTS_SMBIOS) { @@ -365,17 +454,9 @@ static int dmi_sane(fwts_framework *fw, fwts_smbios_entry *entry) uint16_t table_length = entry->struct_table_length; int ret = FWTS_OK; - ptr = table = fwts_mmap((off_t)entry->struct_table_address, - (size_t)table_length); - if (table == FWTS_MAP_FAILED) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, - "SMBIOSTableAddressNotMapped", - "Cannot mmap SMBIOS tables from " - "%8.8" PRIx32 "..%8.8" PRIx32 ".", - entry->struct_table_address, - entry->struct_table_address + table_length); - return FWTS_ERROR; - } + ptr = table = dmi_table_smbios(fw, entry); + if (table == NULL) + return FWTS_ERROR; for (i = 0; i < entry->number_smbios_structures; i++) { if (ptr > table + table_length) { @@ -422,7 +503,7 @@ static int dmi_sane(fwts_framework *fw, fwts_smbios_entry *entry) ret = FWTS_ERROR; } - (void)fwts_munmap(table, (size_t)entry->struct_table_length); + dmi_table_free(table); return ret; } @@ -520,17 +601,9 @@ static int dmi_smbios30_sane(fwts_framework *fw, fwts_smbios30_entry *entry) uint32_t table_length = entry->struct_table_max_size; int ret = FWTS_OK; - ptr = table = fwts_mmap((off_t)entry->struct_table_address, - (size_t)table_length); - if (table == FWTS_MAP_FAILED) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, - "SMBIOS30TableAddressNotMapped", - "Cannot mmap SMBIOS 3.0 tables from " - "%16.16" PRIx64 "..%16.16" PRIx64 ".", - entry->struct_table_address, - entry->struct_table_address + table_length); - return FWTS_ERROR; - } + ptr = table = dmi_table_smbios30(fw, entry); + if (table == NULL) + return FWTS_ERROR; while (1) { @@ -579,7 +652,7 @@ static int dmi_smbios30_sane(fwts_framework *fw, fwts_smbios30_entry *entry) } } - (void)fwts_munmap(table, (size_t)entry->struct_table_max_size); + dmi_table_free(table); return ret; } @@ -1796,7 +1869,6 @@ static int dmicheck_test2(fwts_framework *fw) { void *addr; fwts_smbios_entry entry; - fwts_smbios30_entry entry30; fwts_smbios_type type; uint16_t version = 0; uint8_t *table; @@ -1823,20 +1895,23 @@ static int dmicheck_test2(fwts_framework *fw) if (dmi_version_check(fw, version) != FWTS_OK) return FWTS_SKIP; - table = fwts_mmap((off_t)entry.struct_table_address, - (size_t)entry.struct_table_length); - if (table == FWTS_MAP_FAILED) { - fwts_log_error(fw, "Cannot mmap SMBIOS tables from " - "%8.8" PRIx32 "..%8.8" PRIx32 ".", - entry.struct_table_address, - entry.struct_table_address + entry.struct_table_length); + table = dmi_table_smbios(fw, &entry); + if (table == NULL) return FWTS_ERROR; - } dmi_scan_tables(fw, &entry, table); - (void)fwts_munmap(table, (size_t)entry.struct_table_length); + dmi_table_free(table); + return FWTS_OK; +} + +static int dmicheck_test3(fwts_framework *fw) +{ + void *addr; + fwts_smbios30_entry entry30; + uint16_t version = 0; + uint8_t *table; if (!smbios30_found) { fwts_skipped(fw, "Cannot find SMBIOS30 table entry, skip the test."); @@ -1850,19 +1925,13 @@ static int dmicheck_test2(fwts_framework *fw) return FWTS_ERROR; } - table = fwts_mmap((off_t)entry30.struct_table_address, - (size_t)entry30.struct_table_max_size); - if (table == FWTS_MAP_FAILED) { - fwts_log_error(fw, "Cannot mmap SMBIOS 3.0 table from " - "%16.16" PRIx64 "..%16.16" PRIx64 ".", - entry30.struct_table_address, - entry30.struct_table_address + entry30.struct_table_max_size); + table = dmi_table_smbios30(fw, &entry30); + if (table == NULL) return FWTS_ERROR; - } dmi_scan_smbios30_table(fw, &entry30, table); - (void)fwts_munmap(table, (size_t)entry30.struct_table_max_size); + dmi_table_free(table); return FWTS_OK; } @@ -1870,6 +1939,7 @@ static int dmicheck_test2(fwts_framework *fw) static fwts_framework_minor_test dmicheck_tests[] = { { dmicheck_test1, "Find and test SMBIOS Table Entry Points." }, { dmicheck_test2, "Test DMI/SMBIOS tables for errors." }, + { dmicheck_test3, "Test DMI/SMBIOS3 tables for errors." }, { NULL, NULL } }; diff --git a/src/lib/src/fwts_smbios.c b/src/lib/src/fwts_smbios.c index 8b0d975..4cafb81 100644 --- a/src/lib/src/fwts_smbios.c +++ b/src/lib/src/fwts_smbios.c @@ -17,9 +17,32 @@ * */ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> #include "fwts.h" #if defined(FWTS_ARCH_INTEL) || defined(FWTS_ARCH_AARCH64) + +/* + * fwts_load_file() + * loads file to memory + */ +static int fwts_load_file(const char* filename, void *buf, size_t size) +{ + int fd; + ssize_t ret; + + if ((fd = open(filename, O_RDONLY)) < 0) + return FWTS_ERROR; + ret = read(fd, buf, size); + close(fd); + if (ret != (ssize_t)size) + return FWTS_ERROR; + return FWTS_OK; +} + /* * fwts_smbios_find_entry_uefi() * find SMBIOS structure table entry from UEFI systab @@ -30,15 +53,24 @@ static void *fwts_smbios_find_entry_uefi(fwts_framework *fw, fwts_smbios_entry * fwts_smbios_entry *mapped_entry; if ((addr = fwts_scan_efi_systab("SMBIOS")) != NULL) { - if ((mapped_entry = fwts_mmap((off_t)addr, sizeof(fwts_smbios_entry))) == FWTS_MAP_FAILED) { - fwts_log_error(fw, "Cannot mmap SMBIOS entry at %p\n", addr); - return NULL; + + if ((mapped_entry = fwts_mmap((off_t)addr, sizeof(fwts_smbios_entry))) != FWTS_MAP_FAILED) { + *entry = *mapped_entry; + (void)fwts_munmap(mapped_entry, sizeof(fwts_smbios_entry)); + *type = FWTS_SMBIOS; + return addr; } - *entry = *mapped_entry; - *type = FWTS_SMBIOS; - (void)fwts_munmap(mapped_entry, sizeof(fwts_smbios_entry)); + + if (fwts_load_file("/sys/firmware/dmi/tables/smbios_entry_point", + entry, sizeof(fwts_smbios_entry)) == FWTS_OK && !strncmp((char*)entry, "_SM_", 4)) { + fwts_log_info(fw, "SMBIOS entry loaded from /sys/firmware/dmi/tables/smbios_entry_point\n"); + *type = FWTS_SMBIOS; + return addr; + } + + fwts_log_error(fw, "Cannot mmap SMBIOS entry at %p\n", addr); } - return addr; + return NULL; } /* @@ -51,14 +83,22 @@ static void *fwts_smbios30_find_entry_uefi(fwts_framework *fw, fwts_smbios30_ent fwts_smbios30_entry *mapped_entry; if ((addr = fwts_scan_efi_systab("SMBIOS3")) != NULL) { - if ((mapped_entry = fwts_mmap((off_t)addr, sizeof(fwts_smbios30_entry))) == FWTS_MAP_FAILED) { - fwts_log_error(fw, "Cannot mmap SMBIOS30 entry at %p\n", addr); - return NULL; + + if ((mapped_entry = fwts_mmap((off_t)addr, sizeof(fwts_smbios30_entry))) != FWTS_MAP_FAILED) { + *entry = *mapped_entry; + (void)fwts_munmap(mapped_entry, sizeof(fwts_smbios30_entry)); + return addr; } - *entry = *mapped_entry; - (void)fwts_munmap(mapped_entry, sizeof(fwts_smbios30_entry)); + + if (fwts_load_file("/sys/firmware/dmi/tables/smbios_entry_point", + entry, sizeof(fwts_smbios30_entry)) == FWTS_OK && !strncmp((char*)entry, "_SM3_", 5)) { + fwts_log_info(fw, "SMBIOS30 entry loaded from /sys/firmware/dmi/tables/smbios_entry_point\n"); + return addr; + } + + fwts_log_error(fw, "Cannot mmap SMBIOS30 entry at %p\n", addr); } - return addr; + return NULL; } #if defined(FWTS_ARCH_INTEL)