1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2024 Oxide Computer Company 14 */ 15 16 /* 17 * Test SMBIOS Type 40 Additional Information. We try to cover a variety of 18 * cases with and without entries, entries with and without additional data, and 19 * several invalid length entries. Nothing currently checks that handles are 20 * meaningful beyond that they are replicated. 21 */ 22 23 #include "smbios_test.h" 24 25 static const uint16_t smbios_addinfo_ent0_hdl = 0x7777; 26 static const uint8_t smbios_addinfo_ent0_off = 0x97; 27 static const char *smbios_addinfo_ent0_str = "Sephiroth"; 28 static const uint32_t smbios_addinfo_ent0_data = 9999; 29 static const uint16_t smbios_addinfo_ent1_hdl = 0x1234; 30 static const uint8_t smbios_addinfo_ent1_off = 4; 31 static const char *smbios_addinfo_ent1_str = "Himmel"; 32 static const uint16_t smbios_addinfo_ent2_hdl = 0x4321; 33 static const uint8_t smbios_addinfo_ent2_off = 0xfe; 34 static const char *smbios_addinfo_ent2_str = "Knights of the Round"; 35 static const char *smbios_addinfo_ent2_data = "Galahad, Gawain, Lancelot"; 36 37 static boolean_t 38 smbios_test_addinfo_verify_base(smbios_hdl_t *hdl, smbios_struct_t *sp, 39 uint_t exp) 40 { 41 uint_t nents; 42 boolean_t ret = B_TRUE; 43 smbios_addinfo_ent_t *ent; 44 45 if (smbios_lookup_type(hdl, SMB_TYPE_ADDINFO, sp) == -1) { 46 warnx("failed to lookup SMBIOS addinfo: %s", 47 smbios_errmsg(smbios_errno(hdl))); 48 return (B_FALSE); 49 } 50 51 if (smbios_info_addinfo_nents(hdl, sp->smbstr_id, &nents) != 0) { 52 warnx("failed to get additional information entry count: %s", 53 smbios_errmsg(smbios_errno(hdl))); 54 return (B_FALSE); 55 } 56 57 if (nents != exp) { 58 warnx("additional information entry mismatch: expected 0x%x, " 59 "found 0x%x", exp, nents); 60 ret = B_FALSE; 61 } 62 63 if (smbios_info_addinfo_ent(hdl, sp->smbstr_id, exp, &ent) != -1) { 64 warnx("incorrectly parsed non-existent entity"); 65 smbios_info_addinfo_ent_free(hdl, ent); 66 ret = B_FALSE; 67 } else if (smbios_errno(hdl) != ESMB_REQVAL) { 68 warnx("encountered wrong error for addinfo ent, expected: " 69 "0x%x, found: 0x%x", ESMB_REQVAL, smbios_errno(hdl)); 70 ret = B_FALSE; 71 } 72 73 return (ret); 74 } 75 76 /* 77 * Basic entry without valid entries. Strictly speaking this may be illegal per 78 * the spec. 79 */ 80 boolean_t 81 smbios_test_addinfo_mktable_noent(smbios_test_table_t *table) 82 { 83 smb_addinfo_t add; 84 85 add.smbai_hdr.smbh_type = SMB_TYPE_ADDINFO; 86 add.smbai_hdr.smbh_len = sizeof (add); 87 add.smbai_nents = 0; 88 89 (void) smbios_test_table_append(table, &add, sizeof (add)); 90 smbios_test_table_append_eot(table); 91 92 return (B_TRUE); 93 } 94 95 boolean_t 96 smbios_test_addinfo_verify_noent(smbios_hdl_t *hdl) 97 { 98 smbios_struct_t sp; 99 100 return (smbios_test_addinfo_verify_base(hdl, &sp, 0)); 101 } 102 103 /* 104 * Complex case with three entries, each with varying data and strings. 105 */ 106 boolean_t 107 smbios_test_addinfo_mktable_ents(smbios_test_table_t *table) 108 { 109 smb_addinfo_t add; 110 smb_addinfo_ent_t ent0, ent1, ent2; 111 size_t slen; 112 113 add.smbai_hdr.smbh_type = SMB_TYPE_ADDINFO; 114 add.smbai_hdr.smbh_len = sizeof (add); 115 add.smbai_nents = 3; 116 117 ent0.smbaie_len = sizeof (smb_addinfo_ent_t) + 118 sizeof (smbios_addinfo_ent0_data); 119 ent0.smbaie_rhdl = htole16(smbios_addinfo_ent0_hdl); 120 ent0.smbaie_off = smbios_addinfo_ent0_off; 121 ent0.smbaie_str = 1; 122 add.smbai_hdr.smbh_len += ent0.smbaie_len; 123 124 ent1.smbaie_len = sizeof (smb_addinfo_ent_t); 125 ent1.smbaie_rhdl = htole16(smbios_addinfo_ent1_hdl); 126 ent1.smbaie_off = smbios_addinfo_ent1_off; 127 ent1.smbaie_str = 2; 128 add.smbai_hdr.smbh_len += ent1.smbaie_len; 129 130 slen = strlen(smbios_addinfo_ent2_data) + 1; 131 ent2.smbaie_len = sizeof (smb_addinfo_ent_t) + slen; 132 ent2.smbaie_rhdl = htole16(smbios_addinfo_ent2_hdl); 133 ent2.smbaie_off = smbios_addinfo_ent2_off; 134 ent2.smbaie_str = 3; 135 add.smbai_hdr.smbh_len += ent2.smbaie_len; 136 137 (void) smbios_test_table_append(table, &add, sizeof (add)); 138 (void) smbios_test_table_append_raw(table, &ent0, sizeof (ent0)); 139 (void) smbios_test_table_append_raw(table, &smbios_addinfo_ent0_data, 140 sizeof (smbios_addinfo_ent0_data)); 141 (void) smbios_test_table_append_raw(table, &ent1, sizeof (ent1)); 142 (void) smbios_test_table_append_raw(table, &ent2, sizeof (ent2)); 143 (void) smbios_test_table_append_raw(table, smbios_addinfo_ent2_data, 144 slen); 145 smbios_test_table_append_string(table, smbios_addinfo_ent0_str); 146 smbios_test_table_append_string(table, smbios_addinfo_ent1_str); 147 smbios_test_table_append_string(table, smbios_addinfo_ent2_str); 148 smbios_test_table_str_fini(table); 149 smbios_test_table_append_eot(table); 150 151 return (B_TRUE); 152 } 153 154 boolean_t 155 smbios_test_addinfo_verify_ents(smbios_hdl_t *hdl) 156 { 157 smbios_struct_t sp; 158 boolean_t ret = B_TRUE; 159 smbios_addinfo_ent_t *ent; 160 161 if (!smbios_test_addinfo_verify_base(hdl, &sp, 3)) { 162 return (B_FALSE); 163 } 164 165 if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 0, &ent) != 0) { 166 warnx("failed to lookup additional entry 0: %s", 167 smbios_errmsg(smbios_errno(hdl))); 168 return (B_FALSE); 169 } 170 171 if (ent->smbai_ref != smbios_addinfo_ent0_hdl) { 172 warnx("entry 0 mismatch, found unexpected reference handle: " 173 "0x%lx", ent->smbai_ref); 174 ret = B_FALSE; 175 } 176 if (ent->smbai_ref_off != smbios_addinfo_ent0_off) { 177 warnx("entry 0 mismatch, found unexpected reference offset: " 178 "0x%x", ent->smbai_ref_off); 179 ret = B_FALSE; 180 } 181 if (ent->smbai_dlen != sizeof (smbios_addinfo_ent0_data)) { 182 warnx("entry 0 mismatch, found unexpected data length: 0x%x", 183 ent->smbai_dlen); 184 ret = B_FALSE; 185 } 186 if (memcmp(ent->smbai_data, &smbios_addinfo_ent0_data, 187 ent->smbai_dlen) != 0) { 188 warnx("entry 0 mismatch, additional data mismatched"); 189 ret = B_FALSE; 190 } 191 smbios_info_addinfo_ent_free(hdl, ent); 192 193 if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 1, &ent) != 0) { 194 warnx("failed to lookup additional entry 1: %s", 195 smbios_errmsg(smbios_errno(hdl))); 196 return (B_FALSE); 197 } 198 199 if (ent->smbai_ref != smbios_addinfo_ent1_hdl) { 200 warnx("entry 1 mismatch, found unexpected reference handle: " 201 "0x%lx", ent->smbai_ref); 202 ret = B_FALSE; 203 } 204 if (ent->smbai_ref_off != smbios_addinfo_ent1_off) { 205 warnx("entry 1 mismatch, found unexpected reference offset: " 206 "0x%x", ent->smbai_ref_off); 207 ret = B_FALSE; 208 } 209 if (ent->smbai_dlen != 0) { 210 warnx("entry 1 mismatch, found unexpected data length: 0x%x", 211 ent->smbai_dlen); 212 ret = B_FALSE; 213 } 214 if (ent->smbai_data != NULL) { 215 warnx("entry 1 mismatch, found unexpected data pointer"); 216 ret = B_FALSE; 217 } 218 smbios_info_addinfo_ent_free(hdl, ent); 219 220 if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 2, &ent) != 0) { 221 warnx("failed to lookup additional entry 2: %s", 222 smbios_errmsg(smbios_errno(hdl))); 223 return (B_FALSE); 224 } 225 226 if (ent->smbai_ref != smbios_addinfo_ent2_hdl) { 227 warnx("entry 2 mismatch, found unexpected reference handle: " 228 "0x%lx", ent->smbai_ref); 229 ret = B_FALSE; 230 } 231 if (ent->smbai_ref_off != smbios_addinfo_ent2_off) { 232 warnx("entry 2 mismatch, found unexpected reference offset: " 233 "0x%x", ent->smbai_ref_off); 234 ret = B_FALSE; 235 } 236 if (ent->smbai_dlen != strlen(smbios_addinfo_ent2_data) + 1) { 237 warnx("entry 2 mismatch, found unexpected data length: 0x%x", 238 ent->smbai_dlen); 239 ret = B_FALSE; 240 } 241 if (memcmp(ent->smbai_data, smbios_addinfo_ent2_data, 242 ent->smbai_dlen) != 0) { 243 warnx("entry 2 mismatch, additional data mismatched"); 244 ret = B_FALSE; 245 } 246 smbios_info_addinfo_ent_free(hdl, ent); 247 248 return (ret); 249 } 250 251 /* 252 * Generate a table that's too short to get basic info. 253 */ 254 boolean_t 255 smbios_test_addinfo_mktable_invlen_base(smbios_test_table_t *table) 256 { 257 smb_header_t hdr; 258 259 hdr.smbh_type = SMB_TYPE_ADDINFO; 260 hdr.smbh_len = sizeof (hdr); 261 262 (void) smbios_test_table_append(table, &hdr, sizeof (hdr)); 263 smbios_test_table_append_eot(table); 264 265 return (B_TRUE); 266 } 267 268 boolean_t 269 smbios_test_addinfo_verify_invlen_base(smbios_hdl_t *hdl) 270 { 271 smbios_struct_t sp; 272 uint_t nents; 273 274 if (smbios_lookup_type(hdl, SMB_TYPE_ADDINFO, &sp) == -1) { 275 warnx("failed to lookup SMBIOS addinfo: %s", 276 smbios_errmsg(smbios_errno(hdl))); 277 return (B_FALSE); 278 } 279 280 if (smbios_info_addinfo_nents(hdl, sp.smbstr_id, &nents) != -1) { 281 warnx("accidentally parsed invalid addinfo information as " 282 "valid"); 283 return (B_FALSE); 284 } 285 286 if (smbios_errno(hdl) != ESMB_SHORT) { 287 warnx("encountered wrong error for addinfo, expected: " 288 "0x%x, found: 0x%x", ESMB_SHORT, smbios_errno(hdl)); 289 return (B_FALSE); 290 } 291 292 return (B_TRUE); 293 } 294 295 /* 296 * A table that's long enough to have valid entries, but too short for the first 297 * entry. 298 */ 299 boolean_t 300 smbios_test_addinfo_mktable_invlen_ent(smbios_test_table_t *table) 301 { 302 smb_addinfo_t add; 303 smb_addinfo_ent_t ent = { 0 }; 304 size_t entoff = offsetof(smb_addinfo_ent_t, smbaie_rhdl); 305 306 add.smbai_hdr.smbh_type = SMB_TYPE_ADDINFO; 307 add.smbai_hdr.smbh_len = sizeof (add) + entoff; 308 add.smbai_nents = 1; 309 310 (void) smbios_test_table_append(table, &add, sizeof (add)); 311 (void) smbios_test_table_append_raw(table, &ent, entoff); 312 smbios_test_table_append_eot(table); 313 314 return (B_TRUE); 315 } 316 317 boolean_t 318 smbios_test_addinfo_verify_invlen_ent(smbios_hdl_t *hdl) 319 { 320 smbios_struct_t sp; 321 smbios_addinfo_ent_t *ent; 322 boolean_t ret = B_TRUE; 323 324 if (!smbios_test_addinfo_verify_base(hdl, &sp, 1)) { 325 return (B_FALSE); 326 } 327 328 if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 0, &ent) != -1) { 329 warnx("incorrectly parsed additional information entry 0: " 330 "expected bad length"); 331 ret = B_FALSE; 332 } else if (smbios_errno(hdl) != ESMB_SHORT) { 333 warnx("encountered wrong error for addinfo ent, expected: " 334 "0x%x, found: 0x%x", ESMB_SHORT, smbios_errno(hdl)); 335 ret = B_FALSE; 336 } 337 338 return (ret); 339 } 340 341 /* 342 * Make sure even if we parse the first entity correctly, we fail on the second 343 * one being too short. 344 */ 345 boolean_t 346 smbios_test_addinfo_mktable_invlen_multient(smbios_test_table_t *table) 347 { 348 smb_addinfo_t add; 349 smb_addinfo_ent_t ent0, ent1 = { 0 }; 350 size_t entoff = offsetof(smb_addinfo_ent_t, smbaie_rhdl); 351 352 add.smbai_hdr.smbh_type = SMB_TYPE_ADDINFO; 353 add.smbai_hdr.smbh_len = sizeof (add); 354 add.smbai_nents = 2; 355 356 ent0.smbaie_len = sizeof (smb_addinfo_ent_t) + 357 sizeof (smbios_addinfo_ent0_data); 358 ent0.smbaie_rhdl = htole16(smbios_addinfo_ent0_hdl); 359 ent0.smbaie_off = smbios_addinfo_ent0_off; 360 ent0.smbaie_str = 1; 361 add.smbai_hdr.smbh_len += ent0.smbaie_len; 362 363 ent1.smbaie_len = sizeof (smb_addinfo_ent_t); 364 add.smbai_hdr.smbh_len += entoff; 365 366 (void) smbios_test_table_append(table, &add, sizeof (add)); 367 (void) smbios_test_table_append_raw(table, &ent0, sizeof (ent0)); 368 (void) smbios_test_table_append_raw(table, &smbios_addinfo_ent0_data, 369 sizeof (smbios_addinfo_ent0_data)); 370 (void) smbios_test_table_append_raw(table, &ent1, entoff); 371 372 smbios_test_table_append_string(table, smbios_addinfo_ent0_str); 373 smbios_test_table_str_fini(table); 374 smbios_test_table_append_eot(table); 375 376 377 (void) smbios_test_table_append(table, &add, sizeof (add)); 378 (void) smbios_test_table_append_raw(table, &ent1, entoff); 379 smbios_test_table_append_eot(table); 380 381 return (B_TRUE); 382 } 383 384 boolean_t 385 smbios_test_addinfo_verify_invlen_multient(smbios_hdl_t *hdl) 386 { 387 smbios_struct_t sp; 388 smbios_addinfo_ent_t *ent; 389 boolean_t ret = B_TRUE; 390 391 if (!smbios_test_addinfo_verify_base(hdl, &sp, 2)) { 392 return (B_FALSE); 393 } 394 395 if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 1, &ent) != -1) { 396 warnx("incorrectly parsed additional information entry 1: " 397 "expected bad length"); 398 ret = B_FALSE; 399 } else if (smbios_errno(hdl) != ESMB_SHORT) { 400 warnx("encountered wrong error for addinfo ent, expected: " 401 "0x%x, found: 0x%x", ESMB_SHORT, smbios_errno(hdl)); 402 ret = B_FALSE; 403 } 404 405 if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 0, &ent) != 0) { 406 warnx("failed to lookup additional entry 0: %s", 407 smbios_errmsg(smbios_errno(hdl))); 408 return (B_FALSE); 409 } 410 411 if (ent->smbai_ref != smbios_addinfo_ent0_hdl) { 412 warnx("entry 0 mismatch, found unexpected reference handle: " 413 "0x%lx", ent->smbai_ref); 414 ret = B_FALSE; 415 } 416 if (ent->smbai_ref_off != smbios_addinfo_ent0_off) { 417 warnx("entry 0 mismatch, found unexpected reference offset: " 418 "0x%x", ent->smbai_ref_off); 419 ret = B_FALSE; 420 } 421 if (ent->smbai_dlen != sizeof (smbios_addinfo_ent0_data)) { 422 warnx("entry 0 mismatch, found unexpected data length: 0x%x", 423 ent->smbai_dlen); 424 ret = B_FALSE; 425 } 426 if (memcmp(ent->smbai_data, &smbios_addinfo_ent0_data, 427 ent->smbai_dlen) != 0) { 428 warnx("entry 0 mismatch, additional data mismatched"); 429 ret = B_FALSE; 430 } 431 smbios_info_addinfo_ent_free(hdl, ent); 432 433 return (ret); 434 } 435 436 /* 437 * Make sure we get the case where the length of the entity is longer than the 438 * table. 439 */ 440 boolean_t 441 smbios_test_addinfo_mktable_invlen_entdata(smbios_test_table_t *table) 442 { 443 smb_addinfo_t add; 444 smb_addinfo_ent_t ent; 445 446 add.smbai_hdr.smbh_type = SMB_TYPE_ADDINFO; 447 add.smbai_hdr.smbh_len = sizeof (add) + sizeof (ent); 448 add.smbai_nents = 1; 449 450 (void) memset(&ent, 0, sizeof (ent)); 451 ent.smbaie_len = sizeof (ent) + 3; 452 453 (void) smbios_test_table_append(table, &add, sizeof (add)); 454 (void) smbios_test_table_append_raw(table, &ent, sizeof (ent)); 455 smbios_test_table_append_eot(table); 456 457 return (B_TRUE); 458 } 459 460 boolean_t 461 smbios_test_addinfo_verify_invlen_entdata(smbios_hdl_t *hdl) 462 { 463 smbios_struct_t sp; 464 smbios_addinfo_ent_t *ent; 465 boolean_t ret = B_TRUE; 466 467 if (!smbios_test_addinfo_verify_base(hdl, &sp, 1)) { 468 return (B_FALSE); 469 } 470 471 if (smbios_info_addinfo_ent(hdl, sp.smbstr_id, 0, &ent) != -1) { 472 warnx("incorrectly parsed additional information entry 0: " 473 "expected bad length"); 474 ret = B_FALSE; 475 } else if (smbios_errno(hdl) != ESMB_CORRUPT) { 476 warnx("encountered wrong error for addinfo ent, expected: " 477 "0x%x, found: 0x%x", ESMB_CORRUPT, smbios_errno(hdl)); 478 ret = B_FALSE; 479 } 480 481 return (ret); 482 } 483