Linux PCI subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Leon Romanovsky" <leon@kernel.org>
Cc: linux-input@vger.kernel.org, linux-usb@vger.kernel.org,
	linux-pci@vger.kernel.org, dmitry.torokhov@gmail.com
Subject: Re: [PATCH v2 18/19] PCI: Replace untrusted state with device trust
Date: Tue, 10 Nov 2026 07:35:25 +0000	[thread overview]
Message-ID: <sashiko-outbox-206518@kernel.org> (raw)
In-Reply-To: <20261109-device-trust-core-v2-18-3b12d9a9f861@nvidia.com>

Thank you for your contribution! Sashiko AI review found 5 potential
issues to consider:
- [High] PCI: broken adversarial trust inheritance in
  pci_set_default_trust_policy()
- [High] PCI: default trust policy overwrites adversarial default on
  removable devices
- [Medium] PCI: pci_enable_acs() and pci_ats_init() break
  disabled-to-full trust policy
- [Medium] PCI: pci_dev_ats_permitted() drops PCI_ACS_TB after full
  authorization
- [Medium] PCI: of_create_pci_dev() skips pci_set_default_trust_policy()
  before ATS init
--

commit 7c55633025e040b3c2b6b2f31a6d205ea496c0f7
Author: Leon Romanovsky <leon@kernel.org>

PCI: Replace untrusted state with device trust

This commit replaces pci_dev::untrusted with the generic device trust policy
and trust level helpers across the PCI and IOMMU subsystems.

> diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
> index 9cb23780093dd..c8c96acc26343 100644
> --- a/drivers/pci/ats.c
> +++ b/drivers/pci/ats.c
> @@ -21,7 +21,7 @@ void pci_ats_init(struct pci_dev *dev)
>  {
>  	int pos;
>  
> -	if (pci_ats_disabled() || dev->untrusted)
> +	if (pci_ats_disabled() || pci_dev_default_is_restricted(dev))
>  		return;
>  
>  	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
> @@ -40,7 +40,7 @@ void pci_ats_init(struct pci_dev *dev)
>   */
>  bool pci_ats_supported(struct pci_dev *dev)
>  {
> -	if (!dev->ats_cap || dev->untrusted)
> +	if (!dev->ats_cap)
>  		return false;
>  
>  	if (dev->is_virtfn)
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 7c6f2aba81443..b08adba03f96b 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -1016,8 +1016,9 @@ static void pci_std_enable_acs(struct pci_dev *dev, struct pci_acs *caps)
>  	/* Upstream Forwarding */
>  	caps->ctrl |= (dev->acs_capabilities & PCI_ACS_UF);
>  
> -	/* Enable Translation Blocking for external devices and noats */
> -	if (pci_ats_disabled() || dev->external_facing || dev->untrusted)
> +	/* Enable Translation Blocking when ATS is unavailable or restricted. */
> +	if (pci_ats_disabled() || dev->external_facing ||
> +	    !pci_dev_ats_permitted(dev))
>  		caps->ctrl |= (dev->acs_capabilities & PCI_ACS_TB);
>  }

[Severity: Medium]
Does a device that starts with DEVICE_TRUST_POLICY_DISABLED (for example via
device_trust.default=disabled before initrd authorization or a driver trust
rule) keep ATS disabled and PCI_ACS_TB enabled even after it is authorized for
DEVICE_TRUST_FULL?

During pci_device_add(), pci_ats_init() sees pci_dev_default_is_restricted()
return true and skips initializing dev->ats_cap; nothing re-runs
pci_ats_init() when the device later transitions to DEVICE_TRUST_FULL.
Likewise, device_add() -> iommu_probe_device() -> pci_dma_configure() ->
pci_enable_acs() runs while the device is still unbound
(DEVICE_TRUST_DISABLED), so !pci_dev_ats_permitted(dev) is true and
pci_std_enable_acs() (as well as pci_quirk_enable_intel_spt_pch_acs()) sets
PCI_ACS_TB in hardware.  When really_probe() later sets DEVICE_TRUST_FULL and
calls pci_dma_configure() -> pci_enable_acs() a second time, pci_enable_acs()
reads the existing PCI_ACS_CTRL register value into caps.ctrl and only ORs
bits into it, never clearing PCI_ACS_TB.

> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index 5b6960bbb35bc..607569c31b5b9 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -1738,24 +1738,24 @@ static void set_pcie_cxl(struct pci_dev *dev)
>  
>  }
>  
> -static void set_pcie_untrusted(struct pci_dev *dev)
> +static void pci_set_default_trust_policy(struct pci_dev *dev)
>  {
> -	struct pci_dev *parent = pci_upstream_bridge(dev);
> +	struct pci_dev *parent = pci_physfn(dev);
> +
> +	if (parent == dev)
> +		parent = pci_upstream_bridge(dev);
>  
>  	if (!parent)
>  		return;
> -	/*
> -	 * If the upstream bridge is untrusted we treat this device as
> -	 * untrusted as well.
> -	 */
> -	if (parent->untrusted) {
> -		dev->untrusted = true;
> +
> +	if (device_policy_is_adversarial(&parent->dev)) {
> +		dev->dev.trust_policy = DEVICE_TRUST_POLICY_ADVERSARY;
>  		return;
>  	}
>  
>  	if (arch_pci_dev_is_removable(dev)) {
> -		pci_dbg(dev, "marking as untrusted\n");
> -		dev->untrusted = true;
> +		pci_dbg(dev, "setting adversarial trust policy\n");
> +		dev->dev.trust_policy = DEVICE_TRUST_POLICY_ADVERSARY;
>  	}
>  }

[Severity: High]
Can downstream devices behind a removable PCIe switch or SR-IOV VFs on a
removable PF lose their adversarial default policy when the parent's
trust_policy is overridden?

In pci_setup_device(), device_trust_init(&dev->dev) runs on the parent bridge
before child buses are scanned (or before SR-IOV VFs are created).  If the
parent port or PF has its trust_policy changed to disabled or full (for
example via device_trust.default=disabled, a per-device rule, or sysfs),
device_policy_is_adversarial(&parent->dev) is false for its children.  On x86
ACPI systems, arch_pci_dev_is_removable() only returns true for the switch
upstream port directly beneath an integrated USB4/Thunderbolt root port and
returns false for the switch's downstream ports, endpoints below them, and
VFs:

arch/x86/pci/acpi.c:arch_pci_dev_is_removable() {
	...
	/* Anything directly behind a "usb4-host-interface" is tunneled */
	if (pcie_has_usb4_host_interface(parent))
		return true;

	if (pcie_switch_directly_under(root, pdev))
		return false;
	...
}

Those child devices therefore stay at DEVICE_TRUST_POLICY_DEFAULT and resolve
to DEVICE_TRUST_FULL, bypassing IOMMU DMA domain enforcement, ATS and ACS
restrictions, and SWIOTLB bounce buffering.  Running pci_set_removable(dev)
before pci_set_default_trust_policy(dev) and checking dev_is_removable() would
preserve the hardware removability state across parent policy overrides.

> @@ -2082,7 +2082,7 @@ int pci_setup_device(struct pci_dev *dev)
>  
>  	set_pcie_cxl(dev);
>  
> -	set_pcie_untrusted(dev);
> +	pci_set_default_trust_policy(dev);
>  	device_trust_init(&dev->dev);
>  
>  	/* "Unknown power state" */

[Severity: Medium]
On PowerPC and SPARC systems where of_create_pci_dev() creates PCI devices
directly without calling pci_setup_device(), does pci_ats_init() run before
the device trust policy is initialized?

of_create_pci_dev() calls pci_device_add(), which runs
pci_init_capabilities() -> pci_ats_init() before device_add() calls
device_trust_init(), and never calls pci_set_default_trust_policy().  Because
pci_ats_supported() no longer checks the device state at runtime, dev->ats_cap
is populated while trust_policy is still DEVICE_TRUST_POLICY_DEFAULT, leaving
ATS enabled even when a boot trust policy restricts the device.

> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index aa3765a20a96c..087c63b177c85 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h

[ ... ]

> @@ -616,6 +608,28 @@ static inline struct pci_dev *to_pci_dev(const struct device *dev)
>  {
>  	return container_of(dev, struct pci_dev, dev);
>  }
> +
> +static inline bool
> +pci_dev_default_is_restricted(const struct pci_dev *pdev)
> +{
> +	enum device_trust_policy policy = READ_ONCE(pdev->dev.trust_policy);
> +
> +	return policy == DEVICE_TRUST_POLICY_DISABLED ||
> +	       policy == DEVICE_TRUST_POLICY_ADVERSARY;
> +}

[Severity: High]
If a removable PCI device is configured with an explicit "default" trust
policy (via device_trust=, device_trust.driver=, or sysfs trust_policy), does
that overwrite DEVICE_TRUST_POLICY_ADVERSARY with DEVICE_TRUST_POLICY_DEFAULT
and grant the external device DEVICE_TRUST_FULL?

In pci_setup_device(), device_trust_init() runs after
pci_set_default_trust_policy() and overwrites dev->dev.trust_policy with
DEVICE_TRUST_POLICY_DEFAULT when a per-device default rule matches.  Because
pci_dev_default_is_restricted() only checks for DISABLED and ADVERSARY, and
pci_bus_type does not implement .trust_resolve, DEVICE_TRUST_POLICY_DEFAULT
bypasses pci_dev_default_is_restricted() during discovery and resolves to
DEVICE_TRUST_FULL in __device_trust_prepare() at bind time.

> +static inline bool pci_dev_ats_permitted(const struct pci_dev *pdev)
> +{
> +	enum device_trust_level level = device_get_trust_level(&pdev->dev);
> +	enum device_trust_policy policy = READ_ONCE(pdev->dev.trust_policy);
> +
> +	if (level == DEVICE_TRUST_DISABLED)
> +		return policy != DEVICE_TRUST_POLICY_ADVERSARY &&
> +		       policy != DEVICE_TRUST_POLICY_DISABLED;
> +
> +	return level == DEVICE_TRUST_FULL;
> +}

[Severity: Medium]
Can a device discovered with DEVICE_TRUST_POLICY_DISABLED lose PCI_ACS_TB in
hardware after being authorized for DEVICE_TRUST_FULL and undergoing a PCI
reset or D3cold transition?

At discovery, pci_ats_init() skips setting dev->ats_cap and pci_enable_acs()
sets PCI_ACS_TB because !pci_dev_ats_permitted(dev) is true.  Once the device
is authorized and bound with DEVICE_TRUST_FULL, pci_dev_ats_permitted()
returns true even though dev->ats_cap is 0.  Because ACS registers are not
saved in saved_cap_space, a subsequent reset or D3cold resume clears the
hardware register and runs pci_restore_state() -> pci_enable_acs() ->
pci_std_enable_acs(), which sees pci_dev_ats_permitted() return true and
leaves PCI_ACS_TB cleared.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261109-device-trust-core-v2-0-3b12d9a9f861@nvidia.com?part=18

  parent reply	other threads:[~2026-11-10  7:35 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-09  7:33 [PATCH v2 00/19] driver core: Authorize device trust before driver binding Leon Romanovsky
2026-11-09  7:33 ` [PATCH v2 01/19] Input: gameport - attach manual drivers through the driver core Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-09  7:33 ` [PATCH v2 02/19] wifi: mac80211_hwsim: lock device for manual driver binding Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-09  7:33 ` [PATCH v2 03/19] USB: Lock registered interfaces during " Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-10 14:19     ` Leon Romanovsky
2026-11-09  7:33 ` [PATCH v2 04/19] USB: Release interface claims refused during registration Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-10 14:23     ` Leon Romanovsky
2026-11-09  7:33 ` [PATCH v2 05/19] PNP: Attach card devices through the driver core Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-09  7:33 ` [PATCH v2 06/19] cdx: Propagate DMA configuration errors Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-09  7:33 ` [PATCH v2 07/19] driver core: Report deferred probes through sysfs drivers_probe Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-09  7:33 ` [PATCH v2 08/19] driver core: Add a compatibility API for manual driver attachment Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-09  7:33 ` [PATCH v2 09/19] Input: serio - use the compatibility driver attachment API Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-10 14:29     ` Leon Romanovsky
2026-11-09  7:33 ` [PATCH v2 10/19] net: phy: Use " Leon Romanovsky
2026-11-09 13:45   ` Andrew Lunn
2026-11-10  7:39     ` Leon Romanovsky
2026-11-10 14:31       ` Andrew Lunn
2026-11-10 14:58         ` Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-09  7:33 ` [PATCH v2 11/19] driver core: Introduce a generic device trust level Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-10 15:12     ` Leon Romanovsky
2026-11-09  7:33 ` [PATCH v2 12/19] driver core: Expose device trust authorization interfaces Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-09  7:33 ` [PATCH v2 13/19] driver core: Accept device trust policy on the kernel command line Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-09  7:33 ` [PATCH v2 14/19] driver core: Accept device trust policy by driver name Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-09  7:33 ` [PATCH v2 15/19] driver core: Expose committed device trust level Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-09  7:33 ` [PATCH v2 16/19] driver core: Cover trust authorization and binding with KUnit Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-09  7:33 ` [PATCH v2 17/19] driver core: Document trust admission and initrd authorization Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot
2026-11-09  7:33 ` [PATCH v2 18/19] PCI: Replace untrusted state with device trust Leon Romanovsky
2026-11-09 13:53   ` Robin Murphy
2026-11-10 12:22     ` Leon Romanovsky
2026-11-10 14:25       ` Jason Gunthorpe
2026-11-10 14:34         ` Leon Romanovsky
2026-11-10  7:35   ` sashiko-bot [this message]
2026-11-09  7:33 ` [PATCH v2 19/19] USB: Authorize devices and interfaces through " Leon Romanovsky
2026-11-10  7:35   ` 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-206518@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=dmitry.torokhov@gmail.com \
    --cc=leon@kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-usb@vger.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