summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@fingolfin.org>2021-04-12 10:55:17 -0700
committerRobert Mustacchi <rm@fingolfin.org>2021-04-15 13:44:29 -0700
commit414dafc0a71bccb9c69d6801ed11ba1016a8082b (patch)
tree39878cf4a6d93683ae7b7f3ef2371262b67037af
parent7e85189a2092f2550c3af3a55e22564546838229 (diff)
downloadillumos-joyent-414dafc0a71bccb9c69d6801ed11ba1016a8082b.tar.gz
13714 pcieadm pci check misses renamed nodes
13715 pcieadm save-cfgspace doesn't work with b/d/f 13716 pcieadm save-cfgspace -a can't open files Reviewed by: C Fraire <cfraire@me.com> Reviewed by: Andy Fiddaman <andy@omnios.org> Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r--usr/src/cmd/pcieadm/pcieadm.c51
-rw-r--r--usr/src/cmd/pcieadm/pcieadm.h1
-rw-r--r--usr/src/cmd/pcieadm/pcieadm_cfgspace.c13
-rw-r--r--usr/src/pkg/manifests/system-test-utiltest.mf1
-rw-r--r--usr/src/test/util-tests/runfiles/default.run2
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/Makefile2
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/pcieadm-priv.ksh130
7 files changed, 184 insertions, 16 deletions
diff --git a/usr/src/cmd/pcieadm/pcieadm.c b/usr/src/cmd/pcieadm/pcieadm.c
index edcad6e4d8..f1af0da485 100644
--- a/usr/src/cmd/pcieadm/pcieadm.c
+++ b/usr/src/cmd/pcieadm/pcieadm.c
@@ -129,13 +129,49 @@ pcieadm_ofmt_errx(const char *fmt, ...)
verrx(EXIT_FAILURE, fmt, ap);
}
-boolean_t
+/*
+ * We determine if a node is PCI in a two step process. The first is to see if
+ * the node's name starts with pci, and has an additional character that
+ * indicates it's not the synthetic root of the tree. However, the node name
+ * changes for some classes of devices such as GPUs. As such, for those we try
+ * to look at the compatible property and see if we have a pciexclass or
+ * pciclass entry. We look specifically for the class to make sure that we don't
+ * fall for the synthetic nodes that have a compatible property of
+ * 'pciex_root_complex'.
+ *
+ * The compatible property is a single string that is actually a compressed
+ * string. That is, there are multiple strings concatenated together in a single
+ * pointer.
+ */
+static boolean_t
pcieadm_di_node_is_pci(di_node_t node)
{
const char *name;
+ char *compat;
+ int nents;
name = di_node_name(node);
- return (strncmp("pci", name, 3) == 0);
+ if (strncmp("pci", name, 3) == 0) {
+ return (name[3] != '\0');
+ }
+
+ nents = di_prop_lookup_strings(DDI_DEV_T_ANY, node, "compatible",
+ &compat);
+ if (nents <= 0) {
+ return (B_FALSE);
+ }
+
+ for (int i = 0; i < nents; i++) {
+ if (strncmp("pciclass,", compat, strlen("pciclass,")) == 0 ||
+ strncmp("pciexclass,", compat, strlen("pciexclass,")) ==
+ 0) {
+ return (B_TRUE);
+ }
+
+ compat += strlen(compat) + 1;
+ }
+
+ return (B_FALSE);
}
static int
@@ -147,15 +183,6 @@ pcieadm_di_walk_cb(di_node_t node, void *arg)
return (DI_WALK_CONTINUE);
}
- /*
- * We create synthetic nodes for the root of PCIe tree basically
- * functions as all the resources available for one or more bridges.
- * When we encounter that top-level node skip it.
- */
- if (strcmp("pci", di_node_name(node)) == 0) {
- return (DI_WALK_CONTINUE);
- }
-
return (walk->pdw_func(node, walk->pdw_arg));
}
@@ -216,7 +243,7 @@ pcieadm_find_dip_cb(di_node_t node, void *arg)
}
(void) snprintf(bdf, sizeof (bdf), "%x/%x/%x", PCI_REG_BUS_G(regs[0]),
PCI_REG_DEV_G(regs[0]), PCI_REG_FUNC_G(regs[0]));
- (void) snprintf(bdf, sizeof (bdf), "%02x/%02x/%02x",
+ (void) snprintf(altbdf, sizeof (altbdf), "%02x/%02x/%02x",
PCI_REG_BUS_G(regs[0]), PCI_REG_DEV_G(regs[0]),
PCI_REG_FUNC_G(regs[0]));
diff --git a/usr/src/cmd/pcieadm/pcieadm.h b/usr/src/cmd/pcieadm/pcieadm.h
index b5d44ef970..7ebdc148ca 100644
--- a/usr/src/cmd/pcieadm/pcieadm.h
+++ b/usr/src/cmd/pcieadm/pcieadm.h
@@ -71,7 +71,6 @@ extern void pcieadm_init_cfgspace_file(pcieadm_t *, const char *,
extern void pcieadm_fini_cfgspace_file(void *);
extern void pcieadm_find_nexus(pcieadm_t *);
extern void pcieadm_find_dip(pcieadm_t *, const char *);
-extern boolean_t pcieadm_di_node_is_pci(di_node_t);
/*
* Output related
diff --git a/usr/src/cmd/pcieadm/pcieadm_cfgspace.c b/usr/src/cmd/pcieadm/pcieadm_cfgspace.c
index 50d98c5ec9..32c4be06f4 100644
--- a/usr/src/cmd/pcieadm/pcieadm_cfgspace.c
+++ b/usr/src/cmd/pcieadm/pcieadm_cfgspace.c
@@ -4869,8 +4869,17 @@ pcieadm_save_cfgspace_cb(di_node_t devi, void *arg)
PCI_REG_BUS_G(regs[0]), PCI_REG_DEV_G(regs[0]),
PCI_REG_FUNC_G(regs[0]));
- if ((fd = openat(psc->psc_dirfd, fname, O_WRONLY | O_TRUNC | O_CREAT,
- 0666)) < 0) {
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, psc->psc_pci->pia_priv_eff) !=
+ 0) {
+ err(EXIT_FAILURE, "failed to raise privileges");
+ }
+ fd = openat(psc->psc_dirfd, fname, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, psc->psc_pci->pia_priv_min) !=
+ 0) {
+ err(EXIT_FAILURE, "failed to reduce privileges");
+ }
+
+ if (fd < 0) {
warn("failed to create output file %s", fname);
psc->psc_ret = EXIT_FAILURE;
return (DI_WALK_CONTINUE);
diff --git a/usr/src/pkg/manifests/system-test-utiltest.mf b/usr/src/pkg/manifests/system-test-utiltest.mf
index 44cd0ece10..3bfae2f782 100644
--- a/usr/src/pkg/manifests/system-test-utiltest.mf
+++ b/usr/src/pkg/manifests/system-test-utiltest.mf
@@ -1692,6 +1692,7 @@ file path=opt/util-tests/tests/pci/igb-ltr-p.out mode=0444
file path=opt/util-tests/tests/pci/igb-ltr.out mode=0444
file path=opt/util-tests/tests/pci/igb.pci mode=0444
file path=opt/util-tests/tests/pcidbtest mode=0555
+file path=opt/util-tests/tests/pcieadm-priv mode=0555
file path=opt/util-tests/tests/pcieadmtest mode=0555
file path=opt/util-tests/tests/printf_test mode=0555
file path=opt/util-tests/tests/sed/multi_test mode=0555
diff --git a/usr/src/test/util-tests/runfiles/default.run b/usr/src/test/util-tests/runfiles/default.run
index 248f5b5b82..e65e60b10f 100644
--- a/usr/src/test/util-tests/runfiles/default.run
+++ b/usr/src/test/util-tests/runfiles/default.run
@@ -84,3 +84,5 @@ tests = ['sed_addr', 'multi_test']
[/opt/util-tests/tests/pcidbtest]
[/opt/util-tests/tests/pcieadmtest]
+[/opt/util-tests/tests/pcieadm-priv]
+user = root
diff --git a/usr/src/test/util-tests/tests/pcieadm/Makefile b/usr/src/test/util-tests/tests/pcieadm/Makefile
index 59a995f0ea..dff5374614 100644
--- a/usr/src/test/util-tests/tests/pcieadm/Makefile
+++ b/usr/src/test/util-tests/tests/pcieadm/Makefile
@@ -18,7 +18,7 @@ include $(SRC)/test/Makefile.com
ROOTOPTPKG = $(ROOT)/opt/util-tests/tests
ROOTOPTPCI = $(ROOT)/opt/util-tests/tests/pci
-PROG = pcieadmtest
+PROG = pcieadmtest pcieadm-priv
DATAFILES = bridge.pci igb.pci \
header0-basic.out \
header0-basic-L.out \
diff --git a/usr/src/test/util-tests/tests/pcieadm/pcieadm-priv.ksh b/usr/src/test/util-tests/tests/pcieadm/pcieadm-priv.ksh
new file mode 100644
index 0000000000..0e9c8bc796
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/pcieadm-priv.ksh
@@ -0,0 +1,130 @@
+#!/usr/bin/ksh
+#
+#
+# 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 2021 Oxide Computer Company
+#
+
+#
+# Additional testing for pcieadm that requires us to actually have
+# privileges rather than relying on existing pieces.
+#
+
+unalias -a
+set -o pipefail
+
+pcieadm_arg0="$(basename $0)"
+pcieadm_prog="/usr/lib/pci/pcieadm"
+pcieadm_tmp="/tmp/pcieadm-priv.$$"
+pcieadm_bdf=""
+pcieadm_dev=""
+pcieadm_path=""
+
+warn()
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="failed"
+ echo "TEST FAILED: $pcieadm_arg0: $msg" >&2
+ pcieadm_exit=1
+}
+
+pcieadm_validate_filter()
+{
+ typeset filter="$1"
+
+ if ! $pcieadm_prog show-devs $filter >/dev/null; then
+ warn "failed to show-devs with filter $filter"
+ else
+ printf "TEST PASSED: show-devs $filter\n"
+ fi
+
+ if ! $pcieadm_prog show-cfgspace -d $filter >/dev/null; then
+ warn "failed to show-cfgspace with filter $filter"
+ else
+ printf "TEST PASSED: show-cfgspace -d $filter\n"
+ fi
+
+ if ! $pcieadm_prog save-cfgspace -d $filter "$pcieadm_tmp/out.bin"; then
+ warn "failed to use save-cfgspace -d $filter"
+ else
+ printf "TEST PASSED: save-cfgspace -d $filter\n"
+ fi
+}
+
+#
+# Before we begin execution, set up the environment such that we have a
+# standard locale and that umem will help us catch mistakes.
+#
+export LC_ALL=C.UTF-8
+export LD_PRELOAD=libumem.so
+export UMEM_DEBUG=default
+
+if [[ -n $PCIEADM ]]; then
+ pcieadm_prog=$PCIEADM
+fi
+
+if ! $pcieadm_prog show-devs >/dev/null; then
+ warn "failed to show devices"
+else
+ printf "successfully listed devices\n"
+fi
+
+if ! mkdir "$pcieadm_tmp"; then
+ warn "failed to create temporary directory"
+ exit $pcieadm_exit
+fi
+
+#
+# Verify that we can grab things based on bdf
+#
+pcieadm_bdf=$($pcieadm_prog show-devs -p -o bdf | \
+ awk '{ print $1; exit 0 }')
+if [[ -z "$pcieadm_bdf" ]]; then
+ warn "failed to obtain bdf based filter"
+else
+ pcieadm_validate_filter "$pcieadm_bdf"
+fi
+
+#
+# Verify based on device.
+#
+pcieadm_path=$($pcieadm_prog show-devs -p -o path | \
+ awk '{ print $1; exit 0 }')
+if [[ -z "$pcieadm_path" ]]; then
+ warn "failed to obtain path based filter"
+else
+ pcieadm_validate_filter "$pcieadm_path"
+fi
+
+#
+# Do the same based on the device name
+#
+pcieadm_dev=$($pcieadm_prog show-devs -p -o driver | \
+ awk '{ if ($1 != "--") { print $1; exit 0 } }')
+if [[ -z "$pcieadm_dev" ]]; then
+ warn "failed to obtain driver based filter"
+else
+ pcieadm_validate_filter "$pcieadm_dev"
+fi
+
+if ! $pcieadm_prog save-cfgspace -a "$pcieadm_tmp" > /dev/null; then
+ warn "failed to save all devices"
+else
+ printf "TEST PASSED: save-cfgspace -a\n"
+fi
+
+if (( pcieadm_exit == 0 )); then
+ printf "All tests passed successfully!\n"
+fi
+rm -rf "$pcieadm_tmp"
+exit $pcieadm_exit