From bfb374e014b954371ff0964be8b7ecf78faf5c3e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 11 May 2024 16:57:51 +0200 Subject: [PATCH 1/3] core: split out smbios type 11 reader into src/shared/smbios11.[ch] --- src/core/import-creds.c | 30 ++++---------------- src/shared/meson.build | 1 + src/shared/smbios11.c | 61 +++++++++++++++++++++++++++++++++++++++++ src/shared/smbios11.h | 6 ++++ 4 files changed, 73 insertions(+), 25 deletions(-) create mode 100644 src/shared/smbios11.c create mode 100644 src/shared/smbios11.h diff --git a/src/core/import-creds.c b/src/core/import-creds.c index f27ffed4a0..4008ea43e9 100644 --- a/src/core/import-creds.c +++ b/src/core/import-creds.c @@ -20,6 +20,7 @@ #include "path-util.h" #include "proc-cmdline.h" #include "recurse-dir.h" +#include "smbios11.h" #include "strv.h" #include "virt.h" @@ -578,38 +579,17 @@ static int import_credentials_smbios(ImportCredentialContext *c) { return 0; for (unsigned i = 0;; i++) { - struct dmi_field_header { - uint8_t type; - uint8_t length; - uint16_t handle; - uint8_t count; - char contents[]; - } _packed_ *dmi_field_header; - _cleanup_free_ char *p = NULL; - _cleanup_free_ void *data = NULL; + _cleanup_free_ char *data = NULL; size_t size; - assert_cc(offsetof(struct dmi_field_header, contents) == 5); - - if (asprintf(&p, "/sys/firmware/dmi/entries/11-%u/raw", i) < 0) - return log_oom(); - - r = read_virtual_file(p, sizeof(dmi_field_header) + CREDENTIALS_TOTAL_SIZE_MAX, (char**) &data, &size); + r = read_smbios11_field(i, CREDENTIALS_TOTAL_SIZE_MAX, &data, &size); if (r < 0) { /* Once we reach ENOENT there are no more DMI Type 11 fields around. */ - log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to open '%s', ignoring: %m", p); + log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to read SMBIOS type #11 object %u, ignoring: %m", i); break; } - if (size < offsetof(struct dmi_field_header, contents)) - return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "DMI field header of '%s' too short.", p); - - dmi_field_header = data; - if (dmi_field_header->type != 11 || - dmi_field_header->length != offsetof(struct dmi_field_header, contents)) - return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Invalid DMI field header."); - - r = parse_smbios_strings(c, dmi_field_header->contents, size - offsetof(struct dmi_field_header, contents)); + r = parse_smbios_strings(c, data, size); if (r < 0) return r; diff --git a/src/shared/meson.build b/src/shared/meson.build index c5106d87d5..a1c3b421cc 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -157,6 +157,7 @@ shared_sources = files( 'service-util.c', 'sleep-config.c', 'smack-util.c', + 'smbios11.c', 'socket-label.c', 'socket-netlink.c', 'spawn-ask-password-agent.c', diff --git a/src/shared/smbios11.c b/src/shared/smbios11.c new file mode 100644 index 0000000000..5009427810 --- /dev/null +++ b/src/shared/smbios11.c @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "fileio.h" +#include "macro.h" +#include "smbios11.h" +#include "virt.h" + +int read_smbios11_field(unsigned i, size_t max_size, char **ret_data, size_t *ret_size) { + _cleanup_free_ char *p = NULL, *contents = NULL; + _cleanup_free_ void *data = NULL; + size_t size, contents_size; + int r; + + assert(ret_data); + assert(ret_size); + + /* Parses DMI OEM strings fields (SMBIOS type 11), as settable with qemu's -smbios type=11,value=… switch. */ + + if (detect_container() > 0) /* don't access /sys/ in a container */ + return -ENOENT; + + if (asprintf(&p, "/sys/firmware/dmi/entries/11-%u/raw", i) < 0) + return -ENOMEM; + + struct dmi_field_header { + uint8_t type; + uint8_t length; + uint16_t handle; + uint8_t count; + char contents[]; + } _packed_ *dmi_field_header; + + assert_cc(offsetof(struct dmi_field_header, contents) == 5); + + r = read_virtual_file( + p, + max_size >= SIZE_MAX - offsetof(struct dmi_field_header, contents) ? SIZE_MAX : + sizeof(dmi_field_header) + max_size, + (char**) &data, &size); + if (r < 0) + return r; + + if (size < offsetof(struct dmi_field_header, contents)) + return -EBADMSG; + + dmi_field_header = data; + if (dmi_field_header->type != 11 || + dmi_field_header->length != offsetof(struct dmi_field_header, contents)) + return -EBADMSG; + + contents_size = size - offsetof(struct dmi_field_header, contents); + contents = memdup_suffix0(dmi_field_header->contents, contents_size); + if (!contents) + return -ENOMEM; + + *ret_data = TAKE_PTR(contents); + *ret_size = contents_size; + + return r; /* NB! read_virtual_file() returns 0 on incomplete reads, and 1 in complete reads */ +} diff --git a/src/shared/smbios11.h b/src/shared/smbios11.h new file mode 100644 index 0000000000..ca8fe45260 --- /dev/null +++ b/src/shared/smbios11.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +int read_smbios11_field(unsigned i, size_t max_size, char **ret_data, size_t *ret_size); From 8c5045f9b2681774e8731dc0d142c207b61aedf6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 11 May 2024 16:59:17 +0200 Subject: [PATCH 2/3] analyze: add verb for dumping SMBIOS Type #11 data I find myself wanting to check this data with a quick command, and browsing through /sys/ manually getting binary data sucks. Hence let's do add a nice little analysis tool. --- man/systemd-analyze.xml | 25 ++++++++++++ src/analyze/analyze-smbios11.c | 73 ++++++++++++++++++++++++++++++++++ src/analyze/analyze-smbios11.h | 4 ++ src/analyze/analyze.c | 3 ++ src/analyze/meson.build | 1 + test/units/TEST-65-ANALYZE.sh | 3 ++ 6 files changed, 109 insertions(+) create mode 100644 src/analyze/analyze-smbios11.c create mode 100644 src/analyze/analyze-smbios11.h diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml index 9a4b0cada4..67c7e07778 100644 --- a/man/systemd-analyze.xml +++ b/man/systemd-analyze.xml @@ -186,6 +186,11 @@ architectures NAME + + systemd-analyze + OPTIONS + smbios11 + @@ -979,6 +984,26 @@ x86-64 native + + <command>systemd-analyze smbios11</command> + + Shows a list of SMBIOS Type #11 strings passed to the system. Also see + smbios-type-117. + + + Example output + $ systemd-analyze smbios11 +io.systemd.stub.kernel-cmdline-extra=console=ttyS0 +io.systemd.credential.binary:ssh.ephemeral-authorized_keys-all=c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSURGd20xbFp4WlRGclJteG9ZQlozOTYzcE1uYlJCaDMwM1MxVXhLSUM2NmYgbGVubmFydEB6ZXRhCg== +io.systemd.credential:vmm.notify_socket=vsock-stream:2:254570042 + +3 SMBIOS Type #11 strings passed. + + + + + + diff --git a/src/analyze/analyze-smbios11.c b/src/analyze/analyze-smbios11.c new file mode 100644 index 0000000000..cee5a3ad0b --- /dev/null +++ b/src/analyze/analyze-smbios11.c @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "analyze.h" +#include "analyze-smbios11.h" +#include "escape.h" +#include "smbios11.h" +#include "virt.h" + +int verb_smbios11(int argc, char *argv[], void *userdata) { + unsigned n = 0; + int r; + + for (unsigned i = 0;; i++) { + _cleanup_free_ char *data = NULL; + bool written = false; + size_t size; + + r = read_smbios11_field(i, SIZE_MAX, &data, &size); + if (r == -ENOENT) /* Reached the end */ + break; + if (r < 0) + return log_error_errno(r, "Failed to read SMBIOS Type #11 string %u: %m", i); + bool incomplete = r == 0; + + size_t left, skip; + const char *p; + for (p = data, left = size; left > 0; p += skip, left -= skip) { + const char *nul; + + nul = memchr(p, 0, left); + if (nul) + skip = (nul - p) + 1; + else { + nul = p + left; + skip = left; + } + + if (nul - p == 0) /* Skip empty strings */ + continue; + + _cleanup_free_ char *escaped = NULL; + escaped = cescape_length(p, nul - p); + if (!escaped) + return log_oom(); + + if (written) + fputc('\n', stdout); + + fputs(escaped, stdout); + written = true; + n++; + } + + if (written) { + if (incomplete) + fputs(special_glyph(SPECIAL_GLYPH_ELLIPSIS), stdout); + + fputc('\n', stdout); + } + + if (i == UINT_MAX) /* Prevent overflow */ + break; + } + + if (!arg_quiet) { + if (n == 0) + log_info("No SMBIOS Type #11 strings passed."); + else + log_info("\n%u SMBIOS Type #11 strings passed.", n); + } + + return EXIT_SUCCESS; +} diff --git a/src/analyze/analyze-smbios11.h b/src/analyze/analyze-smbios11.h new file mode 100644 index 0000000000..4b1f334dc8 --- /dev/null +++ b/src/analyze/analyze-smbios11.h @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +int verb_smbios11(int argc, char *argv[], void *userdata); diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index cf4894a9d3..db3996faea 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -34,6 +34,7 @@ #include "analyze-plot.h" #include "analyze-security.h" #include "analyze-service-watchdogs.h" +#include "analyze-smbios11.h" #include "analyze-srk.h" #include "analyze-syscall-filter.h" #include "analyze-time.h" @@ -241,6 +242,7 @@ static int help(int argc, char *argv[], void *userdata) { " image-policy POLICY... Analyze image policy string\n" " pcrs [PCR...] Show TPM2 PCRs and their names\n" " srk [>FILE] Write TPM2 SRK (to FILE)\n" + " smbios11 List strings passed via SMBIOS Type #11\n" "\nOptions:\n" " --recursive-errors=MODE Control which units are verified\n" " --offline=BOOL Perform a security review on unit file(s)\n" @@ -657,6 +659,7 @@ static int run(int argc, char *argv[]) { { "pcrs", VERB_ANY, VERB_ANY, 0, verb_pcrs }, { "srk", VERB_ANY, 1, 0, verb_srk }, { "architectures", VERB_ANY, VERB_ANY, 0, verb_architectures }, + { "smbios11", VERB_ANY, 1, 0, verb_smbios11 }, {} }; diff --git a/src/analyze/meson.build b/src/analyze/meson.build index f150ed7613..a307923c22 100644 --- a/src/analyze/meson.build +++ b/src/analyze/meson.build @@ -22,6 +22,7 @@ systemd_analyze_sources = files( 'analyze-plot.c', 'analyze-security.c', 'analyze-service-watchdogs.c', + 'analyze-smbios11.c', 'analyze-srk.c', 'analyze-syscall-filter.c', 'analyze-time.c', diff --git a/test/units/TEST-65-ANALYZE.sh b/test/units/TEST-65-ANALYZE.sh index 18f5c4d804..fde15192f7 100755 --- a/test/units/TEST-65-ANALYZE.sh +++ b/test/units/TEST-65-ANALYZE.sh @@ -947,6 +947,9 @@ systemd-analyze architectures x86-64 systemd-analyze architectures native systemd-analyze architectures uname +systemd-analyze smbios11 +systemd-analyze smbios11 -q + systemd-analyze log-level info touch /testok From 99db1c959fac8407149ad70523d6d58dc9ce598b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 11 May 2024 17:00:36 +0200 Subject: [PATCH 3/3] update TODO --- TODO | 2 -- 1 file changed, 2 deletions(-) diff --git a/TODO b/TODO index b375327fe0..7bbf334ef1 100644 --- a/TODO +++ b/TODO @@ -179,8 +179,6 @@ Features: * insert the new pidfs inode number as a third field into PidRef, so that PidRef are reasonably serializable without having to pass around fds. -* systemd-analyze smbios11 to dump smbios type 11 vendor strings - * move documentation about our common env vars (SYSTEMD_LOG_LEVEL, SYSTEMD_PAGER, …) into a man page of its own, and just link it from our various man pages that so far embed the whole list again and again, in an