Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion sys/compat/linsysfs/linsysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,22 @@ struct scsi_host_queue {
char *name;
};

TAILQ_HEAD(,scsi_host_queue) scsi_host_q;
struct linsysfs_dmi_field {
const char *name;
const char *kenv;
};

static const struct linsysfs_dmi_field linsysfs_dmi_fields[] = {
{ "sys_vendor", "smbios.system.maker" },
{ "product_name", "smbios.system.product" },
{ "board_vendor", "smbios.planar.maker" },
{ "board_name", "smbios.planar.product" },
{ "bios_vendor", "smbios.bios.vendor" },
{ "bios_version", "smbios.bios.version" },
{ "chassis_vendor", "smbios.chassis.maker" },
};
Comment on lines +65 to +73

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (broader_impact): The /sys/class/dmi/id interface exposes only seven DMI attributes and omits standard fields such as product_uuid, product_serial, product_version, bios_date, board_version, board_serial, chassis_type, and their related fields. Linux applications that probe any of those standard paths receive ENOENT and can still fall back to SMBIOS scanning through /dev/mem, so the new interface does not reliably prevent the fallback described in the PR.

Triggers: When a hardware-identification application requires a standard DMI attribute not included in this table.

Suggested fix: Add the supported non-sensitive standard DMI attributes to linsysfs_dmi_fields, or explicitly limit the interface and callers to the subset that is guaranteed to be available.


TAILQ_HEAD(scsi_host_list, scsi_host_queue) scsi_host_q;

static int host_number = 0;

Expand Down Expand Up @@ -207,6 +222,44 @@ linsysfs_listnics(struct pfs_node *dir)
NULL, NULL, NULL, PFS_RD);
}

static int
linsysfs_dmi_field(PFS_FILL_ARGS)
{
const struct linsysfs_dmi_field *field;
char *value;

field = pn->pn_data;
value = kern_getenv(field->kenv);
if (value == NULL)
return (ENOENT);
sbuf_printf(sb, "%s\n", value);
freeenv(value);
return (0);
}

static void
linsysfs_listdmi(struct pfs_node *class)
{
struct pfs_node *dmi, *id, *node;
size_t i;

dmi = pfs_create_dir(class, "dmi", NULL, NULL, NULL, 0);
id = pfs_create_dir(dmi, "id", NULL, NULL, NULL, 0);
for (i = 0; i < nitems(linsysfs_dmi_fields); i++) {
char *value;

value = kern_getenv(linsysfs_dmi_fields[i].kenv);
if (value == NULL)
continue;
freeenv(value);
node = pfs_create_file(id, linsysfs_dmi_fields[i].name,
&linsysfs_dmi_field, NULL, NULL, NULL, PFS_RD);
if (node != NULL)
node->pn_data = __DECONST(void *,
&linsysfs_dmi_fields[i]);
}
}

/*
* Filler function for proc_name
*/
Expand Down Expand Up @@ -672,6 +725,7 @@ linsysfs_init(PFS_INIT_ARGS)

linsysfs_listcpus(cpu);
linsysfs_listnics(net);
linsysfs_listdmi(class);

/* /sys/kernel */
kernel = pfs_create_dir(root, "kernel", NULL, NULL, NULL, 0);
Expand Down
1 change: 1 addition & 0 deletions tests/sys/fs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ TESTSRC= ${SRCTOP}/contrib/netbsd-tests/fs
.if ${COMPILER_FEATURES:Mc++14} && ${MK_GOOGLETEST} != "no"
TESTS_SUBDIRS+= fusefs
.endif
TESTS_SUBDIRS+= linsysfs
TESTS_SUBDIRS+= tmpfs

${PACKAGE}FILES+= h_funcs.subr
Expand Down
7 changes: 7 additions & 0 deletions tests/sys/fs/linsysfs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
PACKAGE= tests

TESTSDIR= ${TESTSBASE}/sys/fs/linsysfs

ATF_TESTS_SH+= dmi_id_test

.include <bsd.test.mk>
67 changes: 67 additions & 0 deletions tests/sys/fs/linsysfs/dmi_id_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/bin/sh

atf_test_case dmi_id cleanup
dmi_id_head()
{
atf_set "descr" "Verify Linux-compatible DMI identification files"
atf_set "require.user" "root"
}

dmi_id_body()
{
atf_require_prog kenv
atf_require_prog kldload
atf_require_prog kldstat
atf_require_prog mount
atf_require_prog stat
atf_require_prog umount

if ! kldstat -q -m linsysfs; then
atf_check -s exit:0 kldload linsysfs
touch linsysfs_loaded
fi

mkdir mnt
atf_check -s exit:0 mount -t linsysfs linsysfs "$(pwd)/mnt"
touch linsysfs_mounted

found=0
while read -r name key; do
if value=$(kenv "${key}" 2>/dev/null); then
found=1
atf_check -s exit:0 -o inline:"${value}\n" \
cat "mnt/class/dmi/id/${name}"
atf_check -s exit:0 -o inline:"444\n" \
stat -f '%Lp' "mnt/class/dmi/id/${name}"
elif [ -e "mnt/class/dmi/id/${name}" ]; then
atf_fail "${name} exists without ${key}"
fi
done <<-EOF
sys_vendor smbios.system.maker
product_name smbios.system.product
board_vendor smbios.planar.maker
board_name smbios.planar.product
bios_vendor smbios.bios.vendor
bios_version smbios.bios.version
chassis_vendor smbios.chassis.maker
EOF

if [ "${found}" -eq 0 ]; then
atf_skip "no SMBIOS identification values are available"
fi
}

dmi_id_cleanup()
{
if [ -f linsysfs_mounted ]; then
umount "$(pwd)/mnt" >/dev/null 2>&1 || true
fi
if [ -f linsysfs_loaded ]; then
kldunload linsysfs >/dev/null 2>&1 || true
fi
}

atf_init_test_cases()
{
atf_add_test_case dmi_id
}
Loading