From 064d431af1a50617e489660828115f60b99c5c75 Mon Sep 17 00:00:00 2001 From: Robert Mustacchi Date: Sat, 6 Apr 2024 15:27:56 +0000 Subject: [PATCH] 16449 Want smbios additional information (Type 40) decoding Reviewed by: Toomas Soome Reviewed by: Bill Sommerfeld Approved by: Gordon Ross --- usr/src/cmd/smbios/smbios.c | 71 ++- usr/src/common/smbios/smb_error.c | 9 +- usr/src/common/smbios/smb_info.c | 115 ++++- usr/src/lib/libsmbios/common/mapfile-vers | 5 +- usr/src/test/util-tests/tests/smbios/Makefile | 3 +- usr/src/test/util-tests/tests/smbios/smbios.c | 53 ++- usr/src/test/util-tests/tests/smbios/smbios_test.h | 19 +- .../util-tests/tests/smbios/smbios_test_addinfo.c | 482 +++++++++++++++++++++ .../util-tests/tests/smbios/smbios_test_errors.c | 4 +- usr/src/uts/common/sys/smbios.h | 22 +- usr/src/uts/common/sys/smbios_impl.h | 27 +- 11 files changed, 794 insertions(+), 16 deletions(-) create mode 100644 usr/src/test/util-tests/tests/smbios/smbios_test_addinfo.c diff --git a/usr/src/cmd/smbios/smbios.c b/usr/src/cmd/smbios/smbios.c index 9fb692af45..219c4bc20f 100644 --- a/usr/src/cmd/smbios/smbios.c +++ b/usr/src/cmd/smbios/smbios.c @@ -22,7 +22,7 @@ /* * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. * Copyright (c) 2017, Joyent, Inc. - * Copyright 2023 Oxide Computer Company + * Copyright 2024 Oxide Computer Company * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1590,6 +1590,71 @@ print_powersup(smbios_hdl_t *shp, id_t id, FILE *fp) } static void +print_addinfo(smbios_hdl_t *shp, id_t id, FILE *fp) +{ + uint_t nents, i; + + if (smbios_info_addinfo_nents(shp, id, &nents) != 0) { + smbios_warn(shp, "failed to read additional information"); + return; + } + + oprintf(fp, " Number of Additional Information Entries: %u\n", nents); + for (i = 0; i < nents; i++) { + smbios_addinfo_ent_t *ent; + + oprintf(fp, " Additional Information Entry %u\n", i); + if (smbios_info_addinfo_ent(shp, id, i, &ent) != 0) { + smbios_warn(shp, "failed to read additional " + "information entry %u", i); + continue; + } + + oprintf(fp, " Referenced handle: %lu\n", ent->smbai_ref); + oprintf(fp, " Handle offset: %u\n", ent->smbai_ref_off); + if (ent->smbai_str != NULL) { + str_print(fp, " Information String", ent->smbai_str); + } + + /* + * As of SMBIOS 3.7, there are no extra data entries strictly + * defined in the spec, but there may be something. If we find + * something that's a standard integer size, then we'll + * interpret it and print it as a hex value. In theory this is + * supposed to refer back to some field, but hard to say how + * this'll actually be used. The first time we encountered it + * was just an additional string entry. + */ + if (ent->smbai_dlen > 0) { + oprintf(fp, " Data Length: %u\n", ent->smbai_dlen); + switch (ent->smbai_dlen) { + case 1: + oprintf(fp, " Data: 0x%x\n", + *(uint8_t *)ent->smbai_data); + break; + case 2: + oprintf(fp, " Data: 0x%x\n", + *(uint16_t *)ent->smbai_data); + break; + case 4: + oprintf(fp, " Data: 0x%x\n", + *(uint32_t *)ent->smbai_data); + break; + case 8: + oprintf(fp, " Data: 0x%x\n", + *(uint64_t *)ent->smbai_data); + break; + default: + break; + } + } + + smbios_info_addinfo_ent_free(shp, ent); + } +} + + +static void print_processor_info_riscv(smbios_hdl_t *shp, id_t id, FILE *fp) { smbios_processor_info_riscv_t rv; @@ -2048,6 +2113,10 @@ print_struct(smbios_hdl_t *shp, const smbios_struct_t *sp, void *fp) oprintf(fp, "\n"); print_powersup(shp, sp->smbstr_id, fp); break; + case SMB_TYPE_ADDINFO: + oprintf(fp, "\n"); + print_addinfo(shp, sp->smbstr_id, fp); + break; case SMB_TYPE_OBDEVEXT: oprintf(fp, "\n"); print_obdevs_ext(shp, sp->smbstr_id, fp); diff --git a/usr/src/common/smbios/smb_error.c b/usr/src/common/smbios/smb_error.c index 3a393df95a..8bb00bc029 100644 --- a/usr/src/common/smbios/smb_error.c +++ b/usr/src/common/smbios/smb_error.c @@ -23,6 +23,8 @@ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2024 Oxide Computer Company */ #include @@ -45,10 +47,11 @@ static const char *const _smb_errlist[] = { "SMBIOS header checksum mismatch", /* ESMB_CKSUM */ "Invalid argument specified in library call", /* ESMB_INVAL */ "Structure is not of the expected type", /* ESMB_TYPE */ - "Unknown SMBIOS error" /* ESMB_UNKNOWN */ + "Unknown SMBIOS error", /* ESMB_UNKNOWN */ + "Invalid requested value" /* ESMB_REQVAL */ }; -static const int _smb_nerr = sizeof (_smb_errlist) / sizeof (_smb_errlist[0]); +static const size_t _smb_nerr = ARRAY_SIZE(_smb_errlist); const char * smbios_errmsg(int error) @@ -60,7 +63,7 @@ smbios_errmsg(int error) else str = smb_strerror(error); - return (str ? str : "Unknown error"); + return (str != NULL ? str : "Unknown error"); } int diff --git a/usr/src/common/smbios/smb_info.c b/usr/src/common/smbios/smb_info.c index 26c3fc1c2e..3002cf85f6 100644 --- a/usr/src/common/smbios/smb_info.c +++ b/usr/src/common/smbios/smb_info.c @@ -22,7 +22,7 @@ /* * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. * Copyright 2019 Joyent, Inc. - * Copyright 2023 Oxide Computer Company + * Copyright 2024 Oxide Computer Company * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -2151,3 +2151,116 @@ smbios_info_fwinfo_comps_free(smbios_hdl_t *shp, uint_t ncomps, smb_free(comps, sz); } + +int +smbios_info_addinfo_nents(smbios_hdl_t *shp, id_t id, uint_t *nentsp) +{ + const smb_struct_t *stp = smb_lookup_id(shp, id); + smb_addinfo_t add; + + if (stp == NULL) { + return (-1); /* errno is set for us */ + } + + if (stp->smbst_hdr->smbh_type != SMB_TYPE_ADDINFO) { + return (smb_set_errno(shp, ESMB_TYPE)); + } + + if (stp->smbst_hdr->smbh_len < sizeof (add)) { + return (smb_set_errno(shp, ESMB_SHORT)); + } + + smb_info_bcopy(stp->smbst_hdr, &add, sizeof (add)); + *nentsp = add.smbai_nents; + + return (0); +} + +void +smbios_info_addinfo_ent_free(smbios_hdl_t *hdl, smbios_addinfo_ent_t *ent) +{ + if (ent->smbai_dlen > 0) { + ASSERT3P(ent->smbai_data, !=, NULL); + smb_free(ent->smbai_data, ent->smbai_dlen); + } + + smb_free(ent, sizeof (smbios_addinfo_ent_t)); +} + +int +smbios_info_addinfo_ent(smbios_hdl_t *shp, id_t id, uint_t entno, + smbios_addinfo_ent_t **entp) +{ + const smb_struct_t *stp = smb_lookup_id(shp, id); + size_t off; + smb_addinfo_t add; + smb_addinfo_ent_t ent; + smbios_addinfo_ent_t *entry; + uint_t i; + + if (stp == NULL) { + return (-1); /* errno is set for us */ + } + + if (stp->smbst_hdr->smbh_type != SMB_TYPE_ADDINFO) { + return (smb_set_errno(shp, ESMB_TYPE)); + } + + if (stp->smbst_hdr->smbh_len < sizeof (add)) { + return (smb_set_errno(shp, ESMB_SHORT)); + } + + smb_info_bcopy(stp->smbst_hdr, &add, sizeof (add)); + if (entno >= add.smbai_nents) { + return (smb_set_errno(shp, ESMB_REQVAL)); + } + + off = sizeof (add); + for (i = 0; i <= entno; i++) { + if (off + sizeof (ent) > stp->smbst_hdr->smbh_len) { + return (smb_set_errno(shp, ESMB_SHORT)); + } + + smb_info_bcopy_offset(stp->smbst_hdr, &ent, sizeof (ent), off); + if (ent.smbaie_len < sizeof (ent)) { + return (smb_set_errno(shp, ESMB_SHORT)); + } + + if (ent.smbaie_len + off > stp->smbst_hdr->smbh_len) { + return (smb_set_errno(shp, ESMB_CORRUPT)); + } + + if (i != entno) { + off += ent.smbaie_len; + } + } + + entry = smb_alloc(sizeof (smbios_addinfo_ent_t)); + if (entry == NULL) { + return (smb_set_errno(shp, ESMB_NOMEM)); + } + + entry->smbai_ref = ent.smbaie_rhdl; + entry->smbai_ref_off = ent.smbaie_off; + if (ent.smbaie_str != 0) { + entry->smbai_str = smb_strptr(stp, ent.smbaie_str); + } else { + entry->smbai_str = NULL; + } + entry->smbai_dlen = ent.smbaie_len - sizeof (ent); + if (entry->smbai_dlen > 0) { + entry->smbai_data = smb_alloc(entry->smbai_dlen); + if (entry->smbai_data == NULL) { + smb_free(entry, sizeof (smbios_addinfo_ent_t)); + return (smb_set_errno(shp, ESMB_NOMEM)); + } + smb_info_bcopy_offset(stp->smbst_hdr, entry->smbai_data, + entry->smbai_dlen, off + offsetof(smb_addinfo_ent_t, + smbaie_val)); + } else { + entry->smbai_data = NULL; + } + + *entp = entry; + return (0); +} diff --git a/usr/src/lib/libsmbios/common/mapfile-vers b/usr/src/lib/libsmbios/common/mapfile-vers index 10b9185522..abcdbb5eb9 100644 --- a/usr/src/lib/libsmbios/common/mapfile-vers +++ b/usr/src/lib/libsmbios/common/mapfile-vers @@ -22,7 +22,7 @@ # Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. # Copyright (c) 2018, Joyent, Inc. # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright 2021 Oxide Computer Company +# Copyright 2024 Oxide Computer Company # # @@ -44,6 +44,9 @@ $mapfile_version 2 SYMBOL_VERSION SUNWprivate_1.1 { global: _smb_debug { ASSERT = { TYPE = OBJECT; SIZE = 4; }; }; + smbios_info_addinfo_ent; + smbios_info_addinfo_ent_free; + smbios_info_addinfo_nents; smbios_battery_chem_desc; smbios_bboard_flag_desc; smbios_bboard_flag_name; diff --git a/usr/src/test/util-tests/tests/smbios/Makefile b/usr/src/test/util-tests/tests/smbios/Makefile index 886a8648d4..530af0f56b 100644 --- a/usr/src/test/util-tests/tests/smbios/Makefile +++ b/usr/src/test/util-tests/tests/smbios/Makefile @@ -11,7 +11,7 @@ # # Copyright (c) 2018, Joyent, Inc. -# Copyright 2022 Oxide Computer Company +# Copyright 2024 Oxide Computer Company # include $(SRC)/Makefile.master @@ -20,6 +20,7 @@ ROOTOPTPKG = $(ROOT)/opt/util-tests TESTDIR = $(ROOTOPTPKG)/tests/ OBJS = smbios.o \ + smbios_test_addinfo.o \ smbios_test_chassis.o \ smbios_test_errors.o \ smbios_test_extmemdevice.o \ diff --git a/usr/src/test/util-tests/tests/smbios/smbios.c b/usr/src/test/util-tests/tests/smbios/smbios.c index 6154ac6b12..ddd4c09d6e 100644 --- a/usr/src/test/util-tests/tests/smbios/smbios.c +++ b/usr/src/test/util-tests/tests/smbios/smbios.c @@ -11,7 +11,7 @@ /* * Copyright (c) 2018, Joyent, Inc. - * Copyright 2023 Oxide Computer Company + * Copyright 2024 Oxide Computer Company */ /* @@ -584,7 +584,58 @@ static const smbios_test_t smbios_tests[] = { .st_canopen = B_TRUE, .st_verify = smbios_test_extmem_verify_invlen_cs, .st_desc = "SMBIOS Sun extended memory device invalid cs length" + }, +{ + .st_entry = SMBIOS_ENTRY_POINT_30, + .st_tvers = SMB_VERSION, + .st_libvers = SMB_VERSION, + .st_mktable = smbios_test_addinfo_mktable_noent, + .st_canopen = B_TRUE, + .st_verify = smbios_test_addinfo_verify_noent, + .st_desc = "additional information - no entries" + }, { + .st_entry = SMBIOS_ENTRY_POINT_30, + .st_tvers = SMB_VERSION, + .st_libvers = SMB_VERSION, + .st_mktable = smbios_test_addinfo_mktable_ents, + .st_canopen = B_TRUE, + .st_verify = smbios_test_addinfo_verify_ents, + .st_desc = "additional information - multiple entries" + }, { + .st_entry = SMBIOS_ENTRY_POINT_30, + .st_tvers = SMB_VERSION, + .st_libvers = SMB_VERSION, + .st_mktable = smbios_test_addinfo_mktable_invlen_base, + .st_canopen = B_TRUE, + .st_verify = smbios_test_addinfo_verify_invlen_base, + .st_desc = "additional information - invalid length: base" + }, { + .st_entry = SMBIOS_ENTRY_POINT_30, + .st_tvers = SMB_VERSION, + .st_libvers = SMB_VERSION, + .st_mktable = smbios_test_addinfo_mktable_invlen_ent, + .st_canopen = B_TRUE, + .st_verify = smbios_test_addinfo_verify_invlen_ent, + .st_desc = "additional information - invalid length: base entry" + }, { + .st_entry = SMBIOS_ENTRY_POINT_30, + .st_tvers = SMB_VERSION, + .st_libvers = SMB_VERSION, + .st_mktable = smbios_test_addinfo_mktable_invlen_multient, + .st_canopen = B_TRUE, + .st_verify = smbios_test_addinfo_verify_invlen_multient, + .st_desc = "additional information - invalid length: multiple " + "entries" + }, { + .st_entry = SMBIOS_ENTRY_POINT_30, + .st_tvers = SMB_VERSION, + .st_libvers = SMB_VERSION, + .st_mktable = smbios_test_addinfo_mktable_invlen_entdata, + .st_canopen = B_TRUE, + .st_verify = smbios_test_addinfo_verify_invlen_entdata, + .st_desc = "additional information - invalid length: entry data" } +/* XXX Missing an addinfo ent call with the wrong type to verify */ }; static boolean_t diff --git a/usr/src/test/util-tests/tests/smbios/smbios_test.h b/usr/src/test/util-tests/tests/smbios/smbios_test.h index 3b099de56c..6a53c8ecd7 100644 --- a/usr/src/test/util-tests/tests/smbios/smbios_test.h +++ b/usr/src/test/util-tests/tests/smbios/smbios_test.h @@ -10,8 +10,7 @@ */ /* - * Copyright 2019 Robert Mustacchi - * Copyright 2023 Oxide Computer Company + * Copyright 2024 Oxide Computer Company */ #ifndef _SMBIOS_TEST_H @@ -150,7 +149,6 @@ extern boolean_t smbios_test_chassis_verify_comps(smbios_hdl_t *); extern boolean_t smbios_test_chassis_verify_sku_nocomps(smbios_hdl_t *); extern boolean_t smbios_test_chassis_verify_sku(smbios_hdl_t *); - extern boolean_t smbios_test_proc_mktable_25(smbios_test_table_t *); extern boolean_t smbios_test_proc_mktable_36(smbios_test_table_t *); extern boolean_t smbios_test_proc_verify_25(smbios_hdl_t *); @@ -164,6 +162,21 @@ extern boolean_t smbios_test_extmem_verify_invlen_cs(smbios_hdl_t *); extern boolean_t smbios_test_extmem_verify_nocs(smbios_hdl_t *); extern boolean_t smbios_test_extmem_verify_cs(smbios_hdl_t *); +extern boolean_t smbios_test_addinfo_mktable_noent(smbios_test_table_t *); +extern boolean_t smbios_test_addinfo_mktable_ents(smbios_test_table_t *); +extern boolean_t smbios_test_addinfo_mktable_invlen_base(smbios_test_table_t *); +extern boolean_t smbios_test_addinfo_mktable_invlen_ent(smbios_test_table_t *); +extern boolean_t smbios_test_addinfo_mktable_invlen_multient( + smbios_test_table_t *); +extern boolean_t smbios_test_addinfo_mktable_invlen_entdata( + smbios_test_table_t *); +extern boolean_t smbios_test_addinfo_verify_noent(smbios_hdl_t *); +extern boolean_t smbios_test_addinfo_verify_ents(smbios_hdl_t *); +extern boolean_t smbios_test_addinfo_verify_invlen_base(smbios_hdl_t *); +extern boolean_t smbios_test_addinfo_verify_invlen_ent(smbios_hdl_t *); +extern boolean_t smbios_test_addinfo_verify_invlen_multient(smbios_hdl_t *); +extern boolean_t smbios_test_addinfo_verify_invlen_entdata(smbios_hdl_t *); + #ifdef __cplusplus } #endif diff --git a/usr/src/test/util-tests/tests/smbios/smbios_test_addinfo.c b/usr/src/test/util-tests/tests/smbios/smbios_test_addinfo.c new file mode 100644 index 0000000000..f5fdd294ef --- /dev/null +++ b/usr/src/test/util-tests/tests/smbios/smbios_test_addinfo.c @@ -0,0 +1,482 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2024 Oxide Computer Company + */ + +/* + * Test SMBIOS Type 40 Additional Information. We try to cover a variety of + * cases with and without entries, entries with and without additional data, and + * several invalid length entries. Nothing currently checks that handles are + * meaningful beyond that they are replicated. + */ + +#include "smbios_test.h" + +static const uint16_t smbios_addinfo_ent0_hdl = 0x7777; +static const uint8_t smbios_addinfo_ent0_off = 0x97; +static const char *smbios_addinfo_ent0_str = "Sephiroth"; +static const uint32_t smbios_addinfo_ent0_data = 9999; +static const uint16_t smbios_addinfo_ent1_hdl = 0x1234; +static const uint8_t smbios_addinfo_ent1_off = 4; +static const char *smbios_addinfo_ent1_str = "Himmel"; +static const uint16_t smbios_addinfo_ent2_hdl = 0x4321; +static const uint8_t smbios_addinfo_ent2_off = 0xfe; +static const char *smbios_addinfo_ent2_str = "Knights of the Round"; +static const char *smbios_addinfo_ent2_data = "Galahad, Gawain, Lancelot"; + +static boolean_t +smbios_test_addinfo_verify_base(smbios_hdl_t *hdl, smbios_struct_t *sp, + uint_t exp) +{ + uint_t nents; + boolean_t ret = B_TRUE; + smbios_addinfo_ent_t *ent; + + if (smbios_lookup_type(hdl, SMB_TYPE_ADDINFO, sp) == -1) { + warnx("failed to lookup SMBIOS addinfo: %s", + smbios_errmsg(smbios_errno(hdl))); + return (B_FALSE); + } + + if (smbios_info_addinfo_nents(hdl, sp->smbstr_id, &nents) != 0) { + warnx("failed to get additional information entry count: %s", + smbios_errmsg(smbios_errno(hdl))); + return (B_FALSE); + } + + if (nents != exp) { + warnx("additional information entry mismatch: expected 0x%x, " + "found 0x%x", exp, nents); + ret = B_FALSE; + } + + if (smbios_info_addinfo_ent(hdl, sp->smbstr_id, exp, &ent) != -1) { + warnx("incorrectly parsed non-existent entity"); + smbios_info_addinfo_ent_free(hdl, ent); + ret = B_FALSE; + } else if (smbios_errno(hdl) != ESMB_REQVAL) { + warnx("encountered wrong error for addinfo ent, expected: " + "0x%x, found: 0x%x", ESMB_REQVAL, smbios_errno(hdl)); + ret = B_FALSE; + } + + return (ret); +} + +/* + * Basic entry without valid entries. Strictly speaking this may be illegal per + * the spec. + */ +boolean_t +smbios_test_addinfo_mktable_noent(smbios_test_table_t *table) +{ + smb_addinfo_t add; + + add.smbai_hdr.smbh_type = SMB_TYPE_ADDINFO; + add.smbai_hdr.smbh_len = sizeof (add); + add.smbai_nents = 0; + + (void) smbios_test_table_append(table, &add, sizeof (add)); + smbios_test_table_append_eot(table); + + return (B_TRUE); +} + +boolean_t +smbios_test_addinfo_verify_noent(smbios_hdl_t *hdl) +{ + smbios_struct_t sp; + + return (smbios_test_addinfo_verify_base(hdl, &sp, 0)); +} + +/* + * Complex case with three entries, each with varying data and strings. + */ +boolean_t +smbios_test_addinfo_mktable_ents(smbios_test_table_t *table) +{ + smb_addinfo_t add; + smb_addinfo_ent_t ent0, ent1, ent2; + size_t slen; + + add.smbai_hdr.smbh_type = SMB_TYPE_ADDINFO; + add.smbai_hdr.smbh_len = sizeof (add); + add.smbai_nents = 3; + + ent0.smbaie_len = sizeof (smb_addinfo_ent_t) + + sizeof (smbios_addinfo_ent0_data); + ent0.smbaie_rhdl = htole16(smbios_addinfo_ent0_hdl); + ent0.smbaie_off = smbios_addinfo_ent0_off; + ent0.smbaie_str = 1; + add.smbai_hdr.smbh_len += ent0.smbaie_len; + + ent1.smbaie_len = sizeof (smb_addinfo_ent_t); + ent1.smbaie_rhdl = htole16(smbios_addinfo_ent1_hdl); + ent1.smbaie_off = smbios_addinfo_ent1_off; + ent1.smbaie_str = 2; + add.smbai_hdr.smbh_len += ent1.smbaie_len; + + slen = strlen(smbios_addinfo_ent2_data) + 1; + ent2.smbaie_len = sizeof (smb_addinfo_ent_t) + slen; + ent2.smbaie_rhdl = htole16(smbios_addinfo_ent2_hdl); + ent2.smbaie_off = smbios_addinfo_ent2_off; + ent2.smbaie_str = 3; + add.smbai_hdr.smbh_len += ent2.smbaie_len; + + (void) smbios_test_table_append(table, &add, sizeof (add)); + (void) smbios_test_table_append_raw(table, &ent0, sizeof (ent0)); + (void) smbios_test_table_append_raw(table, &smbios_addinfo_ent0_data, + sizeof (smbios_addinfo_ent0_data)); + (void) smbios_test_table_append_raw(table, &ent1, sizeof (ent1)); + (void) smbios_test_table_append_raw(table, &ent2, sizeof (ent2)); + (void) smbios_test_table_append_raw(table, smbios_addinfo_ent2_data, + slen); + smbios_test_table_append_string(table, smbios_addinfo_ent0_str); + smbios_test_table_append_string(table, smbios_addinfo_ent1_str); + smbios_test_table_append_string(table, smbios_addinfo_ent2_str); + smbios_test_table_str_fini(table); + smbios_test_table_append_eot(table); + + return (B_TRUE); +} + +boolean_t +smbios_test_addinfo_verify_ents(smbios_hdl_t *hdl) +{ + smbios_struct_t sp; + boolean_t ret = B_TRUE; + smbios_addinfo_ent_t *ent; + + if (!smbios_test_addinfo_verify_base(hdl, &sp, 3)) { + return (B_FALSE); + } + + if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 0, &ent) != 0) { + warnx("failed to lookup additional entry 0: %s", + smbios_errmsg(smbios_errno(hdl))); + return (B_FALSE); + } + + if (ent->smbai_ref != smbios_addinfo_ent0_hdl) { + warnx("entry 0 mismatch, found unexpected reference handle: " + "0x%lx", ent->smbai_ref); + ret = B_FALSE; + } + if (ent->smbai_ref_off != smbios_addinfo_ent0_off) { + warnx("entry 0 mismatch, found unexpected reference offset: " + "0x%x", ent->smbai_ref_off); + ret = B_FALSE; + } + if (ent->smbai_dlen != sizeof (smbios_addinfo_ent0_data)) { + warnx("entry 0 mismatch, found unexpected data length: 0x%x", + ent->smbai_dlen); + ret = B_FALSE; + } + if (memcmp(ent->smbai_data, &smbios_addinfo_ent0_data, + ent->smbai_dlen) != 0) { + warnx("entry 0 mismatch, additional data mismatched"); + ret = B_FALSE; + } + smbios_info_addinfo_ent_free(hdl, ent); + + if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 1, &ent) != 0) { + warnx("failed to lookup additional entry 1: %s", + smbios_errmsg(smbios_errno(hdl))); + return (B_FALSE); + } + + if (ent->smbai_ref != smbios_addinfo_ent1_hdl) { + warnx("entry 1 mismatch, found unexpected reference handle: " + "0x%lx", ent->smbai_ref); + ret = B_FALSE; + } + if (ent->smbai_ref_off != smbios_addinfo_ent1_off) { + warnx("entry 1 mismatch, found unexpected reference offset: " + "0x%x", ent->smbai_ref_off); + ret = B_FALSE; + } + if (ent->smbai_dlen != 0) { + warnx("entry 1 mismatch, found unexpected data length: 0x%x", + ent->smbai_dlen); + ret = B_FALSE; + } + if (ent->smbai_data != NULL) { + warnx("entry 1 mismatch, found unexpected data pointer"); + ret = B_FALSE; + } + smbios_info_addinfo_ent_free(hdl, ent); + + if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 2, &ent) != 0) { + warnx("failed to lookup additional entry 2: %s", + smbios_errmsg(smbios_errno(hdl))); + return (B_FALSE); + } + + if (ent->smbai_ref != smbios_addinfo_ent2_hdl) { + warnx("entry 2 mismatch, found unexpected reference handle: " + "0x%lx", ent->smbai_ref); + ret = B_FALSE; + } + if (ent->smbai_ref_off != smbios_addinfo_ent2_off) { + warnx("entry 2 mismatch, found unexpected reference offset: " + "0x%x", ent->smbai_ref_off); + ret = B_FALSE; + } + if (ent->smbai_dlen != strlen(smbios_addinfo_ent2_data) + 1) { + warnx("entry 2 mismatch, found unexpected data length: 0x%x", + ent->smbai_dlen); + ret = B_FALSE; + } + if (memcmp(ent->smbai_data, smbios_addinfo_ent2_data, + ent->smbai_dlen) != 0) { + warnx("entry 2 mismatch, additional data mismatched"); + ret = B_FALSE; + } + smbios_info_addinfo_ent_free(hdl, ent); + + return (ret); +} + +/* + * Generate a table that's too short to get basic info. + */ +boolean_t +smbios_test_addinfo_mktable_invlen_base(smbios_test_table_t *table) +{ + smb_header_t hdr; + + hdr.smbh_type = SMB_TYPE_ADDINFO; + hdr.smbh_len = sizeof (hdr); + + (void) smbios_test_table_append(table, &hdr, sizeof (hdr)); + smbios_test_table_append_eot(table); + + return (B_TRUE); +} + +boolean_t +smbios_test_addinfo_verify_invlen_base(smbios_hdl_t *hdl) +{ + smbios_struct_t sp; + uint_t nents; + + if (smbios_lookup_type(hdl, SMB_TYPE_ADDINFO, &sp) == -1) { + warnx("failed to lookup SMBIOS addinfo: %s", + smbios_errmsg(smbios_errno(hdl))); + return (B_FALSE); + } + + if (smbios_info_addinfo_nents(hdl, sp.smbstr_id, &nents) != -1) { + warnx("accidentally parsed invalid addinfo information as " + "valid"); + return (B_FALSE); + } + + if (smbios_errno(hdl) != ESMB_SHORT) { + warnx("encountered wrong error for addinfo, expected: " + "0x%x, found: 0x%x", ESMB_SHORT, smbios_errno(hdl)); + return (B_FALSE); + } + + return (B_TRUE); +} + +/* + * A table that's long enough to have valid entries, but too short for the first + * entry. + */ +boolean_t +smbios_test_addinfo_mktable_invlen_ent(smbios_test_table_t *table) +{ + smb_addinfo_t add; + smb_addinfo_ent_t ent = { 0 }; + size_t entoff = offsetof(smb_addinfo_ent_t, smbaie_rhdl); + + add.smbai_hdr.smbh_type = SMB_TYPE_ADDINFO; + add.smbai_hdr.smbh_len = sizeof (add) + entoff; + add.smbai_nents = 1; + + (void) smbios_test_table_append(table, &add, sizeof (add)); + (void) smbios_test_table_append_raw(table, &ent, entoff); + smbios_test_table_append_eot(table); + + return (B_TRUE); +} + +boolean_t +smbios_test_addinfo_verify_invlen_ent(smbios_hdl_t *hdl) +{ + smbios_struct_t sp; + smbios_addinfo_ent_t *ent; + boolean_t ret = B_TRUE; + + if (!smbios_test_addinfo_verify_base(hdl, &sp, 1)) { + return (B_FALSE); + } + + if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 0, &ent) != -1) { + warnx("incorrectly parsed additional information entry 0: " + "expected bad length"); + ret = B_FALSE; + } else if (smbios_errno(hdl) != ESMB_SHORT) { + warnx("encountered wrong error for addinfo ent, expected: " + "0x%x, found: 0x%x", ESMB_SHORT, smbios_errno(hdl)); + ret = B_FALSE; + } + + return (ret); +} + +/* + * Make sure even if we parse the first entity correctly, we fail on the second + * one being too short. + */ +boolean_t +smbios_test_addinfo_mktable_invlen_multient(smbios_test_table_t *table) +{ + smb_addinfo_t add; + smb_addinfo_ent_t ent0, ent1 = { 0 }; + size_t entoff = offsetof(smb_addinfo_ent_t, smbaie_rhdl); + + add.smbai_hdr.smbh_type = SMB_TYPE_ADDINFO; + add.smbai_hdr.smbh_len = sizeof (add); + add.smbai_nents = 2; + + ent0.smbaie_len = sizeof (smb_addinfo_ent_t) + + sizeof (smbios_addinfo_ent0_data); + ent0.smbaie_rhdl = htole16(smbios_addinfo_ent0_hdl); + ent0.smbaie_off = smbios_addinfo_ent0_off; + ent0.smbaie_str = 1; + add.smbai_hdr.smbh_len += ent0.smbaie_len; + + ent1.smbaie_len = sizeof (smb_addinfo_ent_t); + add.smbai_hdr.smbh_len += entoff; + + (void) smbios_test_table_append(table, &add, sizeof (add)); + (void) smbios_test_table_append_raw(table, &ent0, sizeof (ent0)); + (void) smbios_test_table_append_raw(table, &smbios_addinfo_ent0_data, + sizeof (smbios_addinfo_ent0_data)); + (void) smbios_test_table_append_raw(table, &ent1, entoff); + + smbios_test_table_append_string(table, smbios_addinfo_ent0_str); + smbios_test_table_str_fini(table); + smbios_test_table_append_eot(table); + + + (void) smbios_test_table_append(table, &add, sizeof (add)); + (void) smbios_test_table_append_raw(table, &ent1, entoff); + smbios_test_table_append_eot(table); + + return (B_TRUE); +} + +boolean_t +smbios_test_addinfo_verify_invlen_multient(smbios_hdl_t *hdl) +{ + smbios_struct_t sp; + smbios_addinfo_ent_t *ent; + boolean_t ret = B_TRUE; + + if (!smbios_test_addinfo_verify_base(hdl, &sp, 2)) { + return (B_FALSE); + } + + if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 1, &ent) != -1) { + warnx("incorrectly parsed additional information entry 1: " + "expected bad length"); + ret = B_FALSE; + } else if (smbios_errno(hdl) != ESMB_SHORT) { + warnx("encountered wrong error for addinfo ent, expected: " + "0x%x, found: 0x%x", ESMB_SHORT, smbios_errno(hdl)); + ret = B_FALSE; + } + + if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 0, &ent) != 0) { + warnx("failed to lookup additional entry 0: %s", + smbios_errmsg(smbios_errno(hdl))); + return (B_FALSE); + } + + if (ent->smbai_ref != smbios_addinfo_ent0_hdl) { + warnx("entry 0 mismatch, found unexpected reference handle: " + "0x%lx", ent->smbai_ref); + ret = B_FALSE; + } + if (ent->smbai_ref_off != smbios_addinfo_ent0_off) { + warnx("entry 0 mismatch, found unexpected reference offset: " + "0x%x", ent->smbai_ref_off); + ret = B_FALSE; + } + if (ent->smbai_dlen != sizeof (smbios_addinfo_ent0_data)) { + warnx("entry 0 mismatch, found unexpected data length: 0x%x", + ent->smbai_dlen); + ret = B_FALSE; + } + if (memcmp(ent->smbai_data, &smbios_addinfo_ent0_data, + ent->smbai_dlen) != 0) { + warnx("entry 0 mismatch, additional data mismatched"); + ret = B_FALSE; + } + smbios_info_addinfo_ent_free(hdl, ent); + + return (ret); +} + +/* + * Make sure we get the case where the length of the entity is longer than the + * table. + */ +boolean_t +smbios_test_addinfo_mktable_invlen_entdata(smbios_test_table_t *table) +{ + smb_addinfo_t add; + smb_addinfo_ent_t ent; + + add.smbai_hdr.smbh_type = SMB_TYPE_ADDINFO; + add.smbai_hdr.smbh_len = sizeof (add) + sizeof (ent); + add.smbai_nents = 1; + + (void) memset(&ent, 0, sizeof (ent)); + ent.smbaie_len = sizeof (ent) + 3; + + (void) smbios_test_table_append(table, &add, sizeof (add)); + (void) smbios_test_table_append_raw(table, &ent, sizeof (ent)); + smbios_test_table_append_eot(table); + + return (B_TRUE); +} + +boolean_t +smbios_test_addinfo_verify_invlen_entdata(smbios_hdl_t *hdl) +{ + smbios_struct_t sp; + smbios_addinfo_ent_t *ent; + boolean_t ret = B_TRUE; + + if (!smbios_test_addinfo_verify_base(hdl, &sp, 1)) { + return (B_FALSE); + } + + if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 0, &ent) != -1) { + warnx("incorrectly parsed additional information entry 0: " + "expected bad length"); + ret = B_FALSE; + } else if (smbios_errno(hdl) != ESMB_CORRUPT) { + warnx("encountered wrong error for addinfo ent, expected: " + "0x%x, found: 0x%x", ESMB_CORRUPT, smbios_errno(hdl)); + ret = B_FALSE; + } + + return (ret); +} diff --git a/usr/src/test/util-tests/tests/smbios/smbios_test_errors.c b/usr/src/test/util-tests/tests/smbios/smbios_test_errors.c index eb9895a5f9..284a251edb 100644 --- a/usr/src/test/util-tests/tests/smbios/smbios_test_errors.c +++ b/usr/src/test/util-tests/tests/smbios/smbios_test_errors.c @@ -10,8 +10,7 @@ */ /* - * Copyright 2019 Robert Mustacchi - * Copyright 2021 Oxide Computer Company + * Copyright 2024 Oxide Computer Company */ /* @@ -56,6 +55,7 @@ static smbios_info_func_t smbios_lookup_funcs[] = { { (smbios_lookup_f)smbios_info_tprobe, "tprobe" }, { (smbios_lookup_f)smbios_info_iprobe, "iprobe" }, { (smbios_lookup_f)smbios_info_powersup, "powersup" }, + { (smbios_lookup_f)smbios_info_addinfo_nents, "addinfo" }, { (smbios_lookup_f)smbios_info_pciexrc, "pciexrc" }, { (smbios_lookup_f)smbios_info_processor_info, "processor_info" }, { (smbios_lookup_f)smbios_info_processor_riscv, "processor_riscv" }, diff --git a/usr/src/uts/common/sys/smbios.h b/usr/src/uts/common/sys/smbios.h index f171d6f5b2..f06f7320b0 100644 --- a/usr/src/uts/common/sys/smbios.h +++ b/usr/src/uts/common/sys/smbios.h @@ -22,7 +22,7 @@ /* * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. * Copyright (c) 2018, Joyent, Inc. - * Copyright 2023 Oxide Computer Company + * Copyright 2024 Oxide Computer Company * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1771,6 +1771,21 @@ typedef struct smbios_powersup { #define SMB_POWERSUP_T_REGL 0x08 /* regulator */ /* + * SMBIOS Additional Information. The top level structure defines a number of + * additional information entries, each of which is variable length and intended + * to augment some existing field in the system. Therefore we have a single + * function to get the number of additional entries present and then a different + * one that retrieves each entity function. + */ +typedef struct smbios_addinfo_ent { + id_t smbai_ref; /* referenced handle */ + uint32_t smbai_ref_off; /* offset into referenced handle */ + const char *smbai_str; /* optional string description */ + uint32_t smbai_dlen; /* optional data length */ + void *smbai_data; /* optional data */ +} smbios_addinfo_ent_t; + +/* * SMBIOS Onboard Devices Extended Information. See DSP0134 Section 7.42 * for more information. */ @@ -2120,6 +2135,11 @@ extern int smbios_info_iprobe(smbios_hdl_t *, id_t, smbios_iprobe_t *); extern id_t smbios_info_boot(smbios_hdl_t *, smbios_boot_t *); extern id_t smbios_info_ipmi(smbios_hdl_t *, smbios_ipmi_t *); extern int smbios_info_powersup(smbios_hdl_t *, id_t, smbios_powersup_t *); +extern int smbios_info_addinfo_nents(smbios_hdl_t *, id_t, uint_t *); +extern int smbios_info_addinfo_ent(smbios_hdl_t *, id_t, uint_t, + smbios_addinfo_ent_t **); +extern void smbios_info_addinfo_ent_free(smbios_hdl_t *, + smbios_addinfo_ent_t *); extern int smbios_info_pciexrc(smbios_hdl_t *, id_t, smbios_pciexrc_t *); extern int smbios_info_processor_info(smbios_hdl_t *, id_t, smbios_processor_info_t *); diff --git a/usr/src/uts/common/sys/smbios_impl.h b/usr/src/uts/common/sys/smbios_impl.h index d74eddc79c..709bd720ea 100644 --- a/usr/src/uts/common/sys/smbios_impl.h +++ b/usr/src/uts/common/sys/smbios_impl.h @@ -22,7 +22,7 @@ /* * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. * Copyright (c) 2018, Joyent, Inc. - * Copyright 2023 Oxide Computer Company + * Copyright 2024 Oxide Computer Company * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -625,6 +625,28 @@ typedef struct smb_powersup { #define SMB_PSU_CHARS_TYPE(x) (((x) >> 10) & 0xf) /* + * SMBIOS implementation structure for SMB_TYPE_ADDINFO. + */ +typedef struct smb_addinfo { + smb_header_t smbai_hdr; + uint8_t smbai_nents; + uint8_t smbai_data[]; +} smb_addinfo_t; + +/* + * This contains the additional information entry. There are in theory n of + * these in the smbai_data[] member of the additional information structure + * above. The offset here is to the referenced handle. + */ +typedef struct smb_addinfo_ent { + uint8_t smbaie_len; + uint16_t smbaie_rhdl; + uint8_t smbaie_off; + uint8_t smbaie_str; + uint8_t smbaie_val[]; +} smb_addinfo_ent_t; + +/* * SMBIOS implementation structure for SMB_TYPE_OBDEVEXT. */ typedef struct smb_obdev_ext { @@ -812,7 +834,8 @@ enum { ESMB_CKSUM, /* SMBIOS header checksum mismatch */ ESMB_INVAL, /* invalid function call argument */ ESMB_TYPE, /* structure type mismatch */ - ESMB_UNKNOWN /* unknown error (maximum value tag) */ + ESMB_UNKNOWN, /* unknown error */ + ESMB_REQVAL /* invalid requested value */ }; extern const smb_struct_t *smb_lookup_type(smbios_hdl_t *, uint_t); -- 2.11.4.GIT