From: sashiko-bot@kernel.org
To: alistair23@gmail.com, linux-pci@vger.kernel.org,
linux-cxl@vger.kernel.org
Cc: ojeda@kernel.org, gary@garyguo.net
Subject: Re: [PATCH v6 11/25] PCI/TSM: Support connecting to PCIe CMA devices
Date: Tue, 10 Nov 2026 04:45:12 +0000 [thread overview]
Message-ID: <sashiko-outbox-206234@kernel.org> (raw)
In-Reply-To: <20261110041832.1730924-12-alistair.francis@wdc.com>
Thank you for your contribution! Sashiko AI review found 4 potential
issues to consider:
- [High] PCI/TSM: find_dsm_dev() treats plain CMA PF0/uport as DSM for
subfunctions
- [High] PCI/TSM: probe_fn() constructs subordinate pci_tsm_host without
connect()
- [Medium] PCI/TSM: remove_fn() skips link_sysfs_disable() during
pci_tsm_unregister()
- [Medium] PCI/TSM: disconnect_store() does not verify is_dsm() under
pci_tsm_rwsem
--
commit 71288b5ca3a729f150677c17fac34c3e0b86742a
Author: Alistair Francis <alistair.francis@wdc.com>
PCI/TSM: Support connecting to PCIe CMA devices
This commit adds a helper to distinguish DSM devices from general TSM hosts,
caches CMA DOE mailbox presence on struct pci_dev, and updates TSM connect,
disconnect, and lookup paths to support independent CMA-capable PCIe
functions.
> diff --git a/drivers/pci/tsm.c b/drivers/pci/tsm.c
> index 10c9c6696624d..170e53ae4a0a0 100644
> --- a/drivers/pci/tsm.c
> +++ b/drivers/pci/tsm.c
[ ... ]
> @@ -221,8 +224,13 @@ static int pci_tsm_connect(struct pci_dev *pdev, struct tsm_dev *tsm_dev)
> * is the ultimate arbiter of security state relative to a given
> * interface id, and if it says it can manage TDISP state of a function,
> * let it.
> + *
> + * Only a function in a valid DSM position (function0 or upstream
> + * port) with TEE capability manages subordinate functions. A plain
> + * CMA host manages only itself, leaving sibling functions available
> + * to be connected independently.
> */
> - if (has_tee(pdev))
> + if (has_tee(pdev) && is_pci_tsm_dsm(pdev))
> pci_tsm_walk_fns(pdev, probe_fn, pdev);
> return 0;
> }
[Severity: High]
Can pci_tsm_walk_fns() here still construct a subordinate struct
pci_tsm_host via probe_fn() without ever calling ops->connect()?
When PF0 of a multi-function device (or an upstream switch port) has
PCI_EXP_DEVCAP_TEE set, pci_tsm_connect() walks all sibling or downstream
functions and calls probe_fn() -> ops->probe(). Because
pci_tsm_host_constructor() delegates to pci_tsm_link_constructor() ->
find_dsm_dev() without requiring dsm_dev == pdev, any TSM driver whose
probe() allocates a struct pci_tsm_host for matching devices (such as a CMA
TSM driver matching pdev->doe_cma on PF1, or dsm_probe() in sev-dev-tsm.c
matching is_pci_tsm_dsm() on a downstream endpoint PF0 below an upstream
port DSM) succeeds in probe_fn() with base_tsm.dsm_dev set to the parent DSM
and without ops->connect() running.
For a sibling CMA function, sysfs then reports it as connected and
authenticated while hiding tsm/connect and tsm/disconnect, preventing
userspace from authenticating it. Should pci_tsm_host_constructor() reject
subordinate probing when find_dsm_dev() does not return pdev (or should
subordinate probing be skipped for TSM drivers that only manage self-hosted
connections)?
> @@ -287,6 +295,19 @@ static DEVICE_ATTR_RW(connect);
>
> static int remove_fn(struct pci_dev *pdev, void *data)
> {
> + struct pci_dev *host = data;
> + struct pci_tsm_host *tsm_host;
> +
> + /*
> + * Only teardown the security context of functions that belong to the
> + * DSM being disconnected, leaving any sibling DSM in the same slot
> + * untouched.
> + */
> + if (!pdev->tsm || pdev->tsm->dsm_dev != host)
> + return 0;
> +
> + tsm_host = to_pci_tsm_host(pdev->tsm);
> + guard(mutex)(&tsm_host->lock);
> tsm_remove(pdev->tsm);
> link_sysfs_disable(pdev);
> return 0;
[Severity: Medium]
Does returning early on !pdev->tsm skip link_sysfs_disable() for subordinate
functions during pci_tsm_unregister()?
pci_tsm_unregister() walks PCI devices in reverse order via
for_each_pci_dev_reverse(), visiting VFs and higher-numbered PFs before PF0.
On each subordinate function, __pci_tsm_destroy() only calls
link_sysfs_disable() when is_pci_tsm_host(pdev) && !pci_tsm_link_count, and
then calls pci_tsm_fn_exit() -> tsm_remove(), which clears pdev->tsm to
NULL:
drivers/pci/tsm.c:__pci_tsm_destroy() {
if (is_link_tsm(tsm_dev) && is_pci_tsm_host(pdev) && !pci_tsm_link_count)
link_sysfs_disable(pdev);
...
if (is_link_tsm(tsm_dev) && is_dsm(pdev))
pci_tsm_disconnect(pdev);
else
pci_tsm_fn_exit(pdev);
}
When __pci_tsm_destroy() later reaches the DSM and runs
pci_tsm_disconnect() -> pci_tsm_walk_fns_reverse(pdev, remove_fn, pdev),
pdev->tsm is already NULL on those subordinates, so remove_fn() now returns
early before calling link_sysfs_disable(pdev). That leaves stale sysfs
attribute visibility on VFs and non-host PFs (or on subordinate CMA PFs when
another link TSM remains registered). Calling link_sysfs_disable(pdev) in
pci_tsm_fn_exit() would ensure subordinate sysfs groups are updated before
pdev->tsm is cleared.
[ ... ]
> @@ -587,8 +618,17 @@ static umode_t pci_tsm_attr_visible(struct kobject *kobj,
>
> if (attr == &dev_attr_connect.attr ||
> attr == &dev_attr_disconnect.attr) {
> - if (is_pci_tsm_host(pdev))
> + if (is_pci_tsm_host(pdev)) {
> + /*
> + * Hide while the function is managed by
> + * another DSM, so userspace cannot connect()
> + * it independently or disconnect() a context
> + * that connect() never established.
> + */
> + if (pdev->tsm && !is_dsm(pdev))
> + return 0;
> return attr->mode;
> + }
> }
> }
[Severity: Medium]
Should disconnect_store() also verify is_dsm(pdev) while holding
pci_tsm_rwsem?
pci_tsm_attr_visible() hides tsm/disconnect when pdev->tsm && !is_dsm(pdev),
but if userspace opens a subordinate host-capable function's tsm/disconnect
attribute before its DSM connects and writes to it afterwards,
disconnect_store() only checks !pdev->tsm:
drivers/pci/tsm.c:disconnect_store() {
...
if (!pdev->tsm)
return -ENXIO;
...
pci_tsm_disconnect(pdev);
}
That calls ops->disconnect() and tsm_remove() on a subordinate context that
was never established via ops->connect(). Checking !is_dsm(pdev) in
disconnect_store() prevents this race.
> @@ -662,14 +702,15 @@ static struct pci_dev *find_dsm_dev(struct pci_dev *pdev)
> struct device *grandparent;
> struct pci_dev *uport;
>
> - if (is_pci_tsm_host(pdev))
> - return pdev;
> -
> struct pci_dev *pf0 __free(pci_dev_put) = pf0_dev_get(pdev);
> - if (!pf0)
> - return NULL;
>
> - if (is_dsm(pf0))
> + /*
> + * Functions subordinate to an active DSM are managed by that DSM,
> + * even if the function itself has a CMA DOE mailbox. Check for the
> + * DSM context before considering this function to be its own TSM
> + * host.
> + */
> + if (pf0 && pf0 != pdev && is_dsm(pf0))
> return pf0;
>
> /*
> @@ -677,20 +718,24 @@ static struct pci_dev *find_dsm_dev(struct pci_dev *pdev)
> * downstream devices, check the first upstream port relative to this
> * endpoint.
> */
> - if (!pdev->dev.parent)
> - return NULL;
> - grandparent = pdev->dev.parent->parent;
> - if (!grandparent)
> - return NULL;
> - if (!dev_is_pci(grandparent))
> - return NULL;
> - uport = to_pci_dev(grandparent);
> - if (!pci_is_pcie(uport) ||
> - pci_pcie_type(uport) != PCI_EXP_TYPE_UPSTREAM)
> - return NULL;
> + if (pdev->dev.parent) {
> + grandparent = pdev->dev.parent->parent;
> + if (grandparent && dev_is_pci(grandparent)) {
> + uport = to_pci_dev(grandparent);
> + if (pci_is_pcie(uport) &&
> + pci_pcie_type(uport) == PCI_EXP_TYPE_UPSTREAM &&
> + is_dsm(uport))
> + return uport;
> + }
> + }
> +
> + /*
> + * With no DSM context above it, a TSM host capable function (e.g.
> + * one with a CMA DOE mailbox) is its own host.
> + */
> + if (is_pci_tsm_host(pdev))
> + return pdev;
>
> - if (is_dsm(uport))
> - return uport;
> return NULL;
> }
[Severity: High]
Does find_dsm_dev() misidentify a plain CMA host on PF0 (or on an upstream
port) as the DSM for sibling or downstream functions?
is_dsm() only checks pdev->tsm && pdev->tsm->dsm_dev == pdev, which is true
for any self-hosted connected function, including a plain CMA host without
PCI_EXP_DEVCAP_TEE. When PF0 on a multi-function CMA device is connected
first, pci_tsm_connect() skips subordinate probing because has_tee(pf0) is
false, leaving PF1 to be connected independently. However, when PF1 is
later connected via pci_tsm_connect() -> pci_tsm_host_constructor() ->
pci_tsm_link_constructor() -> find_dsm_dev(pf1), is_dsm(pf0) is true, so
find_dsm_dev(pf1) returns pf0 instead of pf1.
That sets pf1->tsm->dsm_dev = pf0 on PF1's own struct pci_tsm_host:
to_pci_tsm_host(pf1->tsm) then resolves to pf0's pci_tsm_host (using pf0's
lock and DOE mailbox in pci_tsm_doe_transfer()), is_dsm(pf1) becomes false
(hiding PF1's connect and disconnect sysfs attributes), and disconnecting
pf0 or destroying pf1 tears down pf1->tsm via remove_fn() or
pci_tsm_fn_exit() without calling ops->disconnect(pf1).
Should find_dsm_dev() (and pci_tsm_init()) also require has_tee() and
is_pci_tsm_dsm() on pf0 and uport, matching the check in pci_tsm_connect()?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261110041832.1730924-1-alistair.francis@wdc.com?part=11
next prev parent reply other threads:[~2026-11-10 4:45 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-10 4:18 [PATCH v6 00/25] lib: Rust implementation of SPDM alistair23
2026-11-10 4:18 ` [PATCH v6 01/25] virt: coco: change tsm_register() to use a const struct alistair23
2026-11-10 4:27 ` sashiko-bot
2026-11-12 2:39 ` Jonathan Cameron
2026-11-12 3:16 ` Alistair Francis
2026-11-10 4:18 ` [PATCH v6 02/25] rust: create basic untrusted data API alistair23
2026-11-10 4:34 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 03/25] rust: validate: add `Validate` trait alistair23
2026-11-10 4:26 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 04/25] X.509: Make certificate parser public alistair23
2026-11-10 4:26 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 05/25] X.509: Parse Subject Alternative Name in certificates alistair23
2026-11-10 4:26 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 06/25] X.509: Move certificate length retrieval into new helper alistair23
2026-11-10 4:27 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 07/25] rust: add bindings for hash.h alistair23
2026-11-10 4:30 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 08/25] rust: device: Expose Device as_raw() publicly alistair23
2026-11-10 4:26 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 09/25] lib: rspdm: Initial commit of Rust SPDM alistair23
2026-11-10 4:32 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 10/25] PCI/TSM: Rename pf0 to host alistair23
2026-11-10 4:28 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 11/25] PCI/TSM: Support connecting to PCIe CMA devices alistair23
2026-11-10 4:45 ` sashiko-bot [this message]
2026-11-10 4:18 ` [PATCH v6 12/25] PCI/CMA: Add a PCI TSM CMA driver using SPDM alistair23
2026-11-10 4:41 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 13/25] PCI/CMA: Validate Subject Alternative Name in certificates alistair23
2026-11-10 4:40 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 14/25] lib: rspdm: Support SPDM get_version alistair23
2026-11-10 4:32 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 15/25] lib: rspdm: Support SPDM get_capabilities alistair23
2026-11-10 4:38 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 16/25] rust: kernel: Add crypto hash bindings alistair23
2026-11-10 4:37 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 17/25] lib: rspdm: Support SPDM negotiate_algorithms alistair23
2026-11-10 4:42 ` sashiko-bot
2026-11-12 4:50 ` Alistair Francis
2026-11-10 4:18 ` [PATCH v6 18/25] lib: rspdm: Support SPDM get_digests alistair23
2026-11-10 4:42 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 19/25] lib: rspdm: Support SPDM get_certificate alistair23
2026-11-10 4:40 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 20/25] rust: public_key: Add crypto public key bindings alistair23
2026-11-10 4:47 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 21/25] keys: Guard asymmetric-type.h behind CONFIG_KEYS alistair23
2026-11-10 4:41 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 22/25] rust: x509: Add X509 certificate bindings alistair23
2026-11-10 4:54 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 23/25] lib: rspdm: Support SPDM certificate validation alistair23
2026-11-10 4:51 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 24/25] lib: rspdm: Support SPDM challenge alistair23
2026-11-10 4:49 ` sashiko-bot
2026-11-10 4:18 ` [PATCH v6 25/25] lib: rspdm: Expose public Rust API alistair23
2026-11-10 4:53 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-206234@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=alistair23@gmail.com \
--cc=gary@garyguo.net \
--cc=linux-cxl@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=ojeda@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox