From d1bbfaeba56f2eef464b770d2bc60b002b81b9ea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Dec 2024 12:02:33 +0100 Subject: [PATCH 01/10] chid-fundamental: not all SMBIOS fields are available on all systems And the CHID documentation says that CHIDs that require fields that are not available on the local system should not be generated. Follow that, and generate a NULL CHID in that case (which we generally ignore otherwise). --- src/fundamental/chid-fundamental.c | 36 +++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/fundamental/chid-fundamental.c b/src/fundamental/chid-fundamental.c index 9c719a334d..ab366ca8ee 100644 --- a/src/fundamental/chid-fundamental.c +++ b/src/fundamental/chid-fundamental.c @@ -28,7 +28,11 @@ #include "memory-util-fundamental.h" #include "sha1-fundamental.h" -static void get_chid(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], uint32_t mask, EFI_GUID *ret_chid) { +static void get_chid( + const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], + uint32_t mask, + EFI_GUID *ret_chid) { + assert(mask != 0); assert(ret_chid); const EFI_GUID namespace = { UINT32_C(0x12d8ff70), UINT16_C(0x7f4c), UINT16_C(0x7d4c), {} }; /* Swapped to BE */ @@ -38,13 +42,22 @@ static void get_chid(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIE sha1_process_bytes(&namespace, sizeof(namespace), &ctx); - for (unsigned i = 0; i < _CHID_SMBIOS_FIELDS_MAX; i++) - if ((mask >> i) & 1) { - if (i > 0) - sha1_process_bytes(L"&", 2, &ctx); - sha1_process_bytes(smbios_fields[i], strlen16(smbios_fields[i]) * sizeof(char16_t), &ctx); + for (unsigned i = 0; i < _CHID_SMBIOS_FIELDS_MAX; i++) { + if (!((mask >> i) & 1)) + continue; + + if (!smbios_fields[i]) { + /* If some SMBIOS field is missing, don't generate the CHID, as per spec */ + memzero(ret_chid, sizeof(EFI_GUID)); + return; } + if (i > 0) + sha1_process_bytes(L"&", 2, &ctx); + + sha1_process_bytes(smbios_fields[i], strlen16(smbios_fields[i]) * sizeof(char16_t), &ctx); + } + uint8_t hash[SHA1_DIGEST_SIZE]; sha1_finish_ctx(&ctx, hash); @@ -111,9 +124,12 @@ void chid_calculate(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIEL assert(smbios_fields); assert(ret_chids); - for (size_t i = 0; i < CHID_TYPES_MAX; i++) - if (chid_smbios_table[i] != 0) - get_chid(smbios_fields, chid_smbios_table[i], &ret_chids[i]); - else + for (size_t i = 0; i < CHID_TYPES_MAX; i++) { + if (chid_smbios_table[i] == 0) { memzero(&ret_chids[i], sizeof(EFI_GUID)); + continue; + } + + get_chid(smbios_fields, chid_smbios_table[i], &ret_chids[i]); + } } From f8988a5e457a2e9342204414425acb3579e4f646 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Dec 2024 12:03:50 +0100 Subject: [PATCH 02/10] chid-fundamental: make namespace GUID static, too --- src/fundamental/chid-fundamental.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fundamental/chid-fundamental.c b/src/fundamental/chid-fundamental.c index ab366ca8ee..4e2b229bd7 100644 --- a/src/fundamental/chid-fundamental.c +++ b/src/fundamental/chid-fundamental.c @@ -35,11 +35,11 @@ static void get_chid( assert(mask != 0); assert(ret_chid); - const EFI_GUID namespace = { UINT32_C(0x12d8ff70), UINT16_C(0x7f4c), UINT16_C(0x7d4c), {} }; /* Swapped to BE */ struct sha1_ctx ctx = {}; sha1_init_ctx(&ctx); + static const EFI_GUID namespace = { UINT32_C(0x12d8ff70), UINT16_C(0x7f4c), UINT16_C(0x7d4c), {} }; /* Swapped to BE */ sha1_process_bytes(&namespace, sizeof(namespace), &ctx); for (unsigned i = 0; i < _CHID_SMBIOS_FIELDS_MAX; i++) { From 094e2ace12a3cba990dab2768915641e71fbf7a4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Dec 2024 12:04:18 +0100 Subject: [PATCH 03/10] chid-fundamental: use right type to iterate through smbios fields --- src/fundamental/chid-fundamental.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fundamental/chid-fundamental.c b/src/fundamental/chid-fundamental.c index 4e2b229bd7..8a18df3335 100644 --- a/src/fundamental/chid-fundamental.c +++ b/src/fundamental/chid-fundamental.c @@ -42,7 +42,7 @@ static void get_chid( static const EFI_GUID namespace = { UINT32_C(0x12d8ff70), UINT16_C(0x7f4c), UINT16_C(0x7d4c), {} }; /* Swapped to BE */ sha1_process_bytes(&namespace, sizeof(namespace), &ctx); - for (unsigned i = 0; i < _CHID_SMBIOS_FIELDS_MAX; i++) { + for (ChidSmbiosFields i = 0; i < _CHID_SMBIOS_FIELDS_MAX; i++) { if (!((mask >> i) & 1)) continue; From a04af8516e684e2652877c4259188f01be7fe9bb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Dec 2024 18:13:16 +0100 Subject: [PATCH 04/10] chid-fundamental: rework bit checking to use FLAGS_SET() --- src/fundamental/chid-fundamental.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fundamental/chid-fundamental.c b/src/fundamental/chid-fundamental.c index 8a18df3335..b12191b99c 100644 --- a/src/fundamental/chid-fundamental.c +++ b/src/fundamental/chid-fundamental.c @@ -43,7 +43,7 @@ static void get_chid( sha1_process_bytes(&namespace, sizeof(namespace), &ctx); for (ChidSmbiosFields i = 0; i < _CHID_SMBIOS_FIELDS_MAX; i++) { - if (!((mask >> i) & 1)) + if (!FLAGS_SET(mask, UINT32_C(1) << i)) continue; if (!smbios_fields[i]) { From 37e02b455b2e0220a5922e1531d80b406b70b358 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Dec 2024 12:09:41 +0100 Subject: [PATCH 05/10] analyze: not all smbios fields are always defined, deal with that As per previous commit, accept that not all SMBIOS fields are alwaysa available (or set, but empty), hence handle this gracefully and don't generate relevant CHIDs, as per docs. --- src/analyze/analyze-chid.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/analyze/analyze-chid.c b/src/analyze/analyze-chid.c index 5bb50f54d8..9e555e39aa 100644 --- a/src/analyze/analyze-chid.c +++ b/src/analyze/analyze-chid.c @@ -120,11 +120,26 @@ int verb_chid(int argc, char *argv[], void *userdata) { _cleanup_free_ char *buf = NULL; size_t size; + /* According to the CHID spec we should not generate CHIDs for SMBIOS fields that aren't set + * or are set to an empty string. Hence leave them NULL here. */ + + if (!smbios_files[f]) + continue; + r = read_virtual_file_at(smbios_fd, smbios_files[f], SIZE_MAX, &buf, &size); + if (r == -ENOENT) { + log_debug_errno(r, "SMBIOS field '%s' not set, skipping.", smbios_files[f]); + continue; + } if (r < 0) return log_error_errno(r, "Failed to read SMBIOS field '%s': %m", smbios_files[f]); - if (size < 1 || buf[size-1] != '\n') + if (size == 0 || (size == 1 && buf[0] == '\n')) { + log_debug("SMBIOS field '%s' is empty, skipping.", smbios_files[f]); + continue; + } + + if (buf[size-1] != '\n') return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected SMBIOS field '%s' to end in newline, but it doesn't, refusing.", smbios_files[f]); size--; @@ -172,9 +187,13 @@ int verb_chid(int argc, char *argv[], void *userdata) { return log_oom(); for (ChidSmbiosFields f = 0; f < _CHID_SMBIOS_FIELDS_MAX; f++) { - _cleanup_free_ char *c = utf16_to_utf8(smbios_fields[f], SIZE_MAX); - if (!c) - return log_oom(); + _cleanup_free_ char *c = NULL; + + if (smbios_fields[f]) { + c = utf16_to_utf8(smbios_fields[f], SIZE_MAX); + if (!c) + return log_oom(); + } if (!strextend(&legend, ansi_grey(), @@ -191,8 +210,8 @@ int verb_chid(int argc, char *argv[], void *userdata) { smbios_files[f], ansi_grey(), " (", - ansi_highlight(), - c, + c ? ansi_highlight() : ansi_grey(), + strna(c), ansi_grey(), ")", ansi_normal())) @@ -202,7 +221,7 @@ int verb_chid(int argc, char *argv[], void *userdata) { 4 + utf8_console_width(smbios_files[f]) + 2 + - utf8_console_width(c) + + utf8_console_width(strna(c)) + 1; if (w > 79) { From 0f55038c84d83039cec5e4b9aea5997ed6ddd3f9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Dec 2024 12:10:55 +0100 Subject: [PATCH 06/10] analyze-chid: show friendly smbios field names Some of the field names between kernel and smbios spec differ. Kinda confusing. Let's use the smbios field names, to match the CHID spec, which also uses them, and thus be least confusing, treating kernel attribute fields as an internal Linux thing only. --- src/analyze/analyze-chid.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/analyze/analyze-chid.c b/src/analyze/analyze-chid.c index 9e555e39aa..bc562f7b06 100644 --- a/src/analyze/analyze-chid.c +++ b/src/analyze/analyze-chid.c @@ -30,6 +30,15 @@ static int parse_chid_type(const char *s, size_t *ret) { return 0; } +static const char *const chid_smbios_friendly[_CHID_SMBIOS_FIELDS_MAX] = { + [CHID_SMBIOS_MANUFACTURER] = "manufacturer", + [CHID_SMBIOS_FAMILY] = "family", + [CHID_SMBIOS_PRODUCT_NAME] = "product-name", + [CHID_SMBIOS_PRODUCT_SKU] = "product-sku", + [CHID_SMBIOS_BASEBOARD_MANUFACTURER] = "baseboard-manufacturer", + [CHID_SMBIOS_BASEBOARD_PRODUCT] = "baseboard-product", +}; + static const char chid_smbios_fields_char[_CHID_SMBIOS_FIELDS_MAX] = { [CHID_SMBIOS_MANUFACTURER] = 'M', [CHID_SMBIOS_FAMILY] = 'F', @@ -207,7 +216,7 @@ int verb_chid(int argc, char *argv[], void *userdata) { special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), " ", ansi_normal(), - smbios_files[f], + chid_smbios_friendly[f], ansi_grey(), " (", c ? ansi_highlight() : ansi_grey(), @@ -219,7 +228,7 @@ int verb_chid(int argc, char *argv[], void *userdata) { w += separator * 3 + 4 + - utf8_console_width(smbios_files[f]) + + utf8_console_width(chid_smbios_friendly[f]) + 2 + utf8_console_width(strna(c)) + 1; From 95cd07e7727a20fa0c1dcce0bf9c8bc2f650bd4b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Dec 2024 12:12:02 +0100 Subject: [PATCH 07/10] chid: add missing CHID type definitions This add he missing CHID types to our tables, but doesn't add all necessary code to calculate them yet. This brings us closer to what the CHID spec documents, and what "fupwdtool hwids" outputs. --- src/analyze/analyze-chid.c | 10 ++++++++++ src/fundamental/chid-fundamental.c | 29 +++++++++++++++++++++++++++++ src/fundamental/chid-fundamental.h | 5 +++++ src/test/test-chid.c | 7 ++++--- 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/analyze/analyze-chid.c b/src/analyze/analyze-chid.c index bc562f7b06..e89112f23f 100644 --- a/src/analyze/analyze-chid.c +++ b/src/analyze/analyze-chid.c @@ -37,6 +37,11 @@ static const char *const chid_smbios_friendly[_CHID_SMBIOS_FIELDS_MAX] = { [CHID_SMBIOS_PRODUCT_SKU] = "product-sku", [CHID_SMBIOS_BASEBOARD_MANUFACTURER] = "baseboard-manufacturer", [CHID_SMBIOS_BASEBOARD_PRODUCT] = "baseboard-product", + [CHID_SMBIOS_BIOS_VENDOR] = "bios-vendor", + [CHID_SMBIOS_BIOS_VERSION] = "bios-version", + [CHID_SMBIOS_BIOS_MAJOR] = "bios-major", + [CHID_SMBIOS_BIOS_MINOR] = "bios-minor", + [CHID_SMBIOS_ENCLOSURE_TYPE] = "enclosure-type", }; static const char chid_smbios_fields_char[_CHID_SMBIOS_FIELDS_MAX] = { @@ -46,6 +51,11 @@ static const char chid_smbios_fields_char[_CHID_SMBIOS_FIELDS_MAX] = { [CHID_SMBIOS_PRODUCT_SKU] = 'S', [CHID_SMBIOS_BASEBOARD_MANUFACTURER] = 'm', [CHID_SMBIOS_BASEBOARD_PRODUCT] = 'p', + [CHID_SMBIOS_BIOS_VENDOR] = 'B', + [CHID_SMBIOS_BIOS_VERSION] = 'v', + [CHID_SMBIOS_BIOS_MAJOR] = 'R', + [CHID_SMBIOS_BIOS_MINOR] = 'r', + [CHID_SMBIOS_ENCLOSURE_TYPE] = 'e', }; static char *chid_smbios_fields_string(uint32_t combination) { diff --git a/src/fundamental/chid-fundamental.c b/src/fundamental/chid-fundamental.c index b12191b99c..47eabdb349 100644 --- a/src/fundamental/chid-fundamental.c +++ b/src/fundamental/chid-fundamental.c @@ -75,6 +75,30 @@ static void get_chid( } const uint32_t chid_smbios_table[CHID_TYPES_MAX] = { + [0] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | + (UINT32_C(1) << CHID_SMBIOS_FAMILY) | + (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) | + (UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU) | + (UINT32_C(1) << CHID_SMBIOS_BIOS_VENDOR) | + (UINT32_C(1) << CHID_SMBIOS_BIOS_VERSION) | + (UINT32_C(1) << CHID_SMBIOS_BIOS_MAJOR) | + (UINT32_C(1) << CHID_SMBIOS_BIOS_MINOR), + + [1] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | + (UINT32_C(1) << CHID_SMBIOS_FAMILY) | + (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) | + (UINT32_C(1) << CHID_SMBIOS_BIOS_VENDOR) | + (UINT32_C(1) << CHID_SMBIOS_BIOS_VERSION) | + (UINT32_C(1) << CHID_SMBIOS_BIOS_MAJOR) | + (UINT32_C(1) << CHID_SMBIOS_BIOS_MINOR), + + [2] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | + (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) | + (UINT32_C(1) << CHID_SMBIOS_BIOS_VENDOR) | + (UINT32_C(1) << CHID_SMBIOS_BIOS_VERSION) | + (UINT32_C(1) << CHID_SMBIOS_BIOS_MAJOR) | + (UINT32_C(1) << CHID_SMBIOS_BIOS_MINOR), + [3] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_FAMILY) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) | @@ -115,9 +139,14 @@ const uint32_t chid_smbios_table[CHID_TYPES_MAX] = { [11] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_FAMILY), + [12] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | + (UINT32_C(1) << CHID_SMBIOS_ENCLOSURE_TYPE), + [13] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT), + + [14] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER), }; void chid_calculate(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], EFI_GUID ret_chids[static CHID_TYPES_MAX]) { diff --git a/src/fundamental/chid-fundamental.h b/src/fundamental/chid-fundamental.h index 41f7be337d..48b1343f5c 100644 --- a/src/fundamental/chid-fundamental.h +++ b/src/fundamental/chid-fundamental.h @@ -20,6 +20,11 @@ typedef enum ChidSmbiosFields { CHID_SMBIOS_PRODUCT_SKU, CHID_SMBIOS_BASEBOARD_MANUFACTURER, CHID_SMBIOS_BASEBOARD_PRODUCT, + CHID_SMBIOS_BIOS_VENDOR, + CHID_SMBIOS_BIOS_VERSION, + CHID_SMBIOS_BIOS_MAJOR, + CHID_SMBIOS_BIOS_MINOR, + CHID_SMBIOS_ENCLOSURE_TYPE, _CHID_SMBIOS_FIELDS_MAX, } ChidSmbiosFields; diff --git a/src/test/test-chid.c b/src/test/test-chid.c index ae1726679d..2faf886c97 100644 --- a/src/test/test-chid.c +++ b/src/test/test-chid.c @@ -11,6 +11,7 @@ const char16_t *const test_fields[_CHID_SMBIOS_FIELDS_MAX] = { [CHID_SMBIOS_FAMILY] = u"To be filled by O.E.M.", [CHID_SMBIOS_BASEBOARD_PRODUCT] = u"MPG X670E CARBON WIFI (MS-7D70)", [CHID_SMBIOS_BASEBOARD_MANUFACTURER] = u"Micro-Star International Co., Ltd.", + [CHID_SMBIOS_ENCLOSURE_TYPE] = u"3", }; /* Actual output of `fwupdtool hwids`: @@ -51,7 +52,7 @@ Extra Hardware IDs {7b3d90ce-ed79-5951-a48a-764ea9f11146} <- Manufacturer + BiosVendor */ -static const EFI_GUID actual_chids[] = { +static const EFI_GUID actual_chids[CHID_TYPES_MAX] = { {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, @@ -64,9 +65,9 @@ static const EFI_GUID actual_chids[] = { {0xc12c1f4a, 0x332d, 0x5d72, {0xaa, 0x36, 0x7a, 0x3d, 0x41, 0x3b, 0x47, 0x9a}}, {0x28ac9cf2, 0x5bde, 0x59f7, {0xae, 0xbe, 0x4b, 0x3d, 0x00, 0x80, 0x90, 0xfe}}, {0xe821e0e2, 0xe11a, 0x5e94, {0xbf, 0x5d, 0xff, 0xe5, 0x3c, 0x5e, 0x50, 0x48}}, - {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {0xbdd76d3e, 0x147f, 0x58a9, {0xa0, 0xb2, 0x42, 0x13, 0x64, 0x54, 0xed, 0x07}}, {0xb2e58e8b, 0xfb10, 0x5cd0, {0x8f, 0xb0, 0x5b, 0xd9, 0x31, 0xf1, 0x87, 0x1a}}, - {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {0x50af5797, 0xa2f2, 0x58b1, {0x9a, 0x1a, 0x45, 0x3b, 0xcb, 0xb2, 0xe0, 0x25}}, }; TEST(chid) { From 6b99f3ba5a11a442635fb4cb3397dd7ee8d87af6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Dec 2024 12:13:43 +0100 Subject: [PATCH 08/10] analyze: C escape weird chars in SMBIOS fields just in case, let's not write garbled crap to the TTY but escape and potential weird chars before output. --- src/analyze/analyze-chid.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/analyze/analyze-chid.c b/src/analyze/analyze-chid.c index e89112f23f..22f7b6d603 100644 --- a/src/analyze/analyze-chid.c +++ b/src/analyze/analyze-chid.c @@ -4,6 +4,7 @@ #include "analyze-chid.h" #include "chid-fundamental.h" #include "efi-api.h" +#include "escape.h" #include "fd-util.h" #include "fileio.h" #include "format-table.h" @@ -209,7 +210,13 @@ int verb_chid(int argc, char *argv[], void *userdata) { _cleanup_free_ char *c = NULL; if (smbios_fields[f]) { - c = utf16_to_utf8(smbios_fields[f], SIZE_MAX); + _cleanup_free_ char *u = NULL; + + u = utf16_to_utf8(smbios_fields[f], SIZE_MAX); + if (!u) + return log_oom(); + + c = cescape(u); if (!c) return log_oom(); } From 0eb51d99137a81a66b1e6c5e0915f354ca47d8a8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Dec 2024 12:20:09 +0100 Subject: [PATCH 09/10] analyze-chid: split out code that reads smbios into helper --- src/analyze/analyze-chid.c | 41 ++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/analyze/analyze-chid.c b/src/analyze/analyze-chid.c index 22f7b6d603..7cc51ae405 100644 --- a/src/analyze/analyze-chid.c +++ b/src/analyze/analyze-chid.c @@ -107,7 +107,7 @@ static void smbios_fields_free(char16_t *(*fields)[_CHID_SMBIOS_FIELDS_MAX]) { free(*i); } -int verb_chid(int argc, char *argv[], void *userdata) { +static int smbios_fields_acquire(char16_t *fields[static _CHID_SMBIOS_FIELDS_MAX]) { static const char *const smbios_files[_CHID_SMBIOS_FIELDS_MAX] = { [CHID_SMBIOS_MANUFACTURER] = "sys_vendor", @@ -118,24 +118,12 @@ int verb_chid(int argc, char *argv[], void *userdata) { [CHID_SMBIOS_BASEBOARD_PRODUCT] = "board_name", }; - _cleanup_(table_unrefp) Table *table = NULL; int r; - if (detect_container() > 0) - return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Container environments do not have SMBIOS."); - - table = table_new("type", "input", "chid"); - if (!table) - return log_oom(); - - (void) table_set_align_percent(table, table_get_cell(table, 0, 0), 100); - (void) table_set_align_percent(table, table_get_cell(table, 0, 1), 50); - _cleanup_close_ int smbios_fd = open("/sys/class/dmi/id", O_RDONLY|O_DIRECTORY|O_CLOEXEC); if (smbios_fd < 0) return log_error_errno(errno, "Failed to open SMBIOS sysfs object: %m"); - _cleanup_(smbios_fields_free) char16_t* smbios_fields[_CHID_SMBIOS_FIELDS_MAX] = {}; for (ChidSmbiosFields f = 0; f < _CHID_SMBIOS_FIELDS_MAX; f++) { _cleanup_free_ char *buf = NULL; size_t size; @@ -164,11 +152,34 @@ int verb_chid(int argc, char *argv[], void *userdata) { size--; - smbios_fields[f] = utf8_to_utf16(buf, size); - if (!smbios_fields[f]) + fields[f] = utf8_to_utf16(buf, size); + if (!fields[f]) return log_oom(); } + return 0; +} + +int verb_chid(int argc, char *argv[], void *userdata) { + + _cleanup_(table_unrefp) Table *table = NULL; + int r; + + if (detect_container() > 0) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Container environments do not have SMBIOS."); + + table = table_new("type", "input", "chid"); + if (!table) + return log_oom(); + + (void) table_set_align_percent(table, table_get_cell(table, 0, 0), 100); + (void) table_set_align_percent(table, table_get_cell(table, 0, 1), 50); + + _cleanup_(smbios_fields_free) char16_t* smbios_fields[_CHID_SMBIOS_FIELDS_MAX] = {}; + r = smbios_fields_acquire(smbios_fields); + if (r < 0) + return r; + EFI_GUID chids[CHID_TYPES_MAX] = {}; chid_calculate((const char16_t* const*) smbios_fields, chids); From 8ca50bde48746f04f14d1de3d0db904950e60994 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Dec 2024 12:21:01 +0100 Subject: [PATCH 10/10] analyze-chid: fully support all CHID types This adds logic to read the missing SMBIOS fields from userspace, too. With this we should have full CHID coverage now, matching fwupd's output fully. --- src/analyze/analyze-chid.c | 63 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/analyze/analyze-chid.c b/src/analyze/analyze-chid.c index 7cc51ae405..0916e60c1f 100644 --- a/src/analyze/analyze-chid.c +++ b/src/analyze/analyze-chid.c @@ -116,6 +116,11 @@ static int smbios_fields_acquire(char16_t *fields[static _CHID_SMBIOS_FIELDS_MAX [CHID_SMBIOS_PRODUCT_SKU] = "product_sku", [CHID_SMBIOS_BASEBOARD_MANUFACTURER] = "board_vendor", [CHID_SMBIOS_BASEBOARD_PRODUCT] = "board_name", + [CHID_SMBIOS_BIOS_VENDOR] = "bios_vendor", + [CHID_SMBIOS_BIOS_VERSION] = "bios_version", + [CHID_SMBIOS_BIOS_MAJOR] = "bios_release", + [CHID_SMBIOS_BIOS_MINOR] = "bios_release", + [CHID_SMBIOS_ENCLOSURE_TYPE] = "chassis_type", }; int r; @@ -150,8 +155,66 @@ static int smbios_fields_acquire(char16_t *fields[static _CHID_SMBIOS_FIELDS_MAX if (buf[size-1] != '\n') return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected SMBIOS field '%s' to end in newline, but it doesn't, refusing.", smbios_files[f]); + buf[size-1] = 0; size--; + switch (f) { + + case CHID_SMBIOS_BIOS_MAJOR: + case CHID_SMBIOS_BIOS_MINOR: { + /* The kernel exposes this a string ., split them apart again. */ + char *dot = memchr(buf, '.', size); + if (!dot) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "BIOS release field '%s' contains no dot?", smbios_files[f]); + + const char *p; + if (f == CHID_SMBIOS_BIOS_MAJOR) { + *dot = 0; + p = buf; + } else { + assert(f == CHID_SMBIOS_BIOS_MINOR); + p = dot + 1; + } + + /* The kernel exports the enclosure in decimal, we need it in hex (zero left-padded) */ + + uint8_t u; + r = safe_atou8(p, &u); + if (r < 0) + return log_error_errno(r, "Failed to parse BIOS release: %s", p); + + buf = mfree(buf); + if (asprintf(&buf, "%02x", u) < 0) + return log_oom(); + + size = strlen(buf); + break; + } + + case CHID_SMBIOS_ENCLOSURE_TYPE: { + /* The kernel exports the enclosure in decimal, we need it in hex (no padding!) */ + + uint8_t u; + r = safe_atou8(buf, &u); + if (r < 0) + return log_error_errno(r, "Failed to parse enclosure type: %s", buf); + + buf = mfree(buf); + if (u == 0) + buf = strdup(""); /* zero is mapped to empty string */ + else + (void) asprintf(&buf, "%x", u); + if (!buf) + return log_oom(); + + size = strlen(buf); + break; + } + + default: + break; + } + fields[f] = utf8_to_utf16(buf, size); if (!fields[f]) return log_oom();