All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.