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
smbios_test_addinfo_verify_base(smbios_hdl_t * hdl,smbios_struct_t * sp,uint_t exp)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
smbios_test_addinfo_mktable_noent(smbios_test_table_t * table)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
smbios_test_addinfo_verify_noent(smbios_hdl_t * hdl)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
smbios_test_addinfo_mktable_ents(smbios_test_table_t * table)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
smbios_test_addinfo_verify_ents(smbios_hdl_t * hdl)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%" _PRIxID, 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%" _PRIxID, 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%" _PRIxID, 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
smbios_test_addinfo_mktable_invlen_base(smbios_test_table_t * table)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
smbios_test_addinfo_verify_invlen_base(smbios_hdl_t * hdl)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
smbios_test_addinfo_mktable_invlen_ent(smbios_test_table_t * table)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
smbios_test_addinfo_verify_invlen_ent(smbios_hdl_t * hdl)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
smbios_test_addinfo_mktable_invlen_multient(smbios_test_table_t * table)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
smbios_test_addinfo_verify_invlen_multient(smbios_hdl_t * hdl)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%" _PRIxID, 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
smbios_test_addinfo_mktable_invlen_entdata(smbios_test_table_t * table)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
smbios_test_addinfo_verify_invlen_entdata(smbios_hdl_t * hdl)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