All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bjorn Helgaas <helgaas@kernel.org>
To: Gary Guo <gary@garyguo.net>
Cc: Bjorn Helgaas <bhelgaas@google.com>,
	Zhenzhong Duan <zhenzhong.duan@gmail.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	"Rafael J. Wysocki" <rafael@kernel.org>,
	Danilo Krummrich <dakr@kernel.org>,
	Damien Le Moal <dlemoal@kernel.org>,
	Niklas Cassel <cassel@kernel.org>,
	GOTO Masanori <gotom@debian.or.jp>,
	YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>,
	"James E.J. Bottomley" <James.Bottomley@hansenpartnership.com>,
	"Martin K. Petersen" <martin.petersen@oracle.com>,
	Vaibhav Gupta <vaibhavgupta40@gmail.com>,
	Jens Taprogge <jens.taprogge@taprogge.org>,
	Ido Schimmel <idosch@nvidia.com>, Petr Machata <petrm@nvidia.com>,
	Andrew Lunn <andrew+netdev@lunn.ch>,
	"David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	David Airlie <airlied@redhat.com>,
	linux-pci@vger.kernel.org, driver-core@lists.linux.dev,
	linux-kernel@vger.kernel.org, linux-ide@vger.kernel.org,
	linux-scsi@vger.kernel.org,
	industrypack-devel@lists.sourceforge.net, netdev@vger.kernel.org,
	dri-devel@lists.freedesktop.org, Sashiko <sashiko-bot@kernel.org>
Subject: Re: [PATCH v3 9/9] pci: fix UAF when probe runs concurrent to dyn ID removal
Date: Tue, 21 Jul 2026 17:35:00 -0500	[thread overview]
Message-ID: <20260721223500.GA690676@bhelgaas> (raw)
In-Reply-To: <20260706-pci_id_fix-v3-9-2d48fc025acc@garyguo.net>

On Mon, Jul 06, 2026 at 03:11:21PM +0100, Gary Guo wrote:
> Dynamic IDs are only guaranteed to be valid when dynids.lock is held,
> as remove_id_store can free the node. Thus, make a copy in
> pci_match_device. Also, clarify that the id parameter is only valid during
> probe.
> 
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Link: https://lore.kernel.org/all/20260619170503.518F61F00A3A@smtp.kernel.org/
> Fixes: 0994375e9614 ("PCI: add remove_id sysfs entry")
> Signed-off-by: Gary Guo <gary@garyguo.net>
> ---
>  drivers/pci/pci-driver.c | 28 +++++++++++++++-------------
>  include/linux/pci.h      |  1 +
>  2 files changed, 16 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
> index 2e80ae150ff4..4851061babcb 100644
> --- a/drivers/pci/pci-driver.c
> +++ b/drivers/pci/pci-driver.c
> @@ -179,6 +179,7 @@ static const struct pci_device_id pci_device_id_any = {
>   * pci_match_device - See if a device matches a driver's list of IDs
>   * @drv: the PCI driver to match against
>   * @dev: the PCI device structure to match against
> + * @id_copy: Place to store copy of pci_device_id for dynamic ID

s/Place/place/ (capitalize same as the others)

>   * Used by a driver to check whether a PCI device is in its list of
>   * supported devices or in the dynids list, which may have been augmented
> @@ -186,9 +187,9 @@ static const struct pci_device_id pci_device_id_any = {
>   * structure or %NULL if there is no match.
>   */
>  static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
> -						    struct pci_dev *dev)
> +						    struct pci_dev *dev,
> +						    struct pci_device_id *id_copy)
>  {
> -	struct pci_dynid *dynid;
>  	const struct pci_device_id *found_id = NULL;
>  	struct pci_device_id dev_id;
>  	int ret;
> @@ -200,17 +201,16 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
>  
>  	dev_id = pci_id_from_device(dev);
>  	/* Look at the dynamic ids first, before the static ones */
> -	spin_lock(&drv->dynids.lock);
> -	list_for_each_entry(dynid, &drv->dynids.list, node) {
> -		if (pci_match_one_id(&dynid->id, &dev_id)) {
> -			found_id = &dynid->id;
> -			break;
> +	scoped_guard(spinlock, &drv->dynids.lock) {
> +		struct pci_dynid *dynid;
> +
> +		list_for_each_entry(dynid, &drv->dynids.list, node) {
> +			if (pci_match_one_id(&dynid->id, &dev_id)) {
> +				*id_copy = dynid->id;
> +				return id_copy;
> +			}
>  		}
>  	}
> -	spin_unlock(&drv->dynids.lock);
> -
> -	if (found_id)
> -		return found_id;
>  
>  	found_id = do_pci_match_id(drv->id_table, &dev_id, ret > 0);
>  	if (found_id)
> @@ -466,12 +466,13 @@ void pci_probe_flush_workqueue(void)
>  static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
>  {
>  	const struct pci_device_id *id;
> +	struct pci_device_id id_copy;
>  	int error = 0;
>  
>  	if (drv->probe) {
>  		error = -ENODEV;
>  
> -		id = pci_match_device(drv, pci_dev);
> +		id = pci_match_device(drv, pci_dev, &id_copy);
>  		if (id)
>  			error = pci_call_probe(drv, pci_dev, id);
>  	}
> @@ -1559,12 +1560,13 @@ static int pci_bus_match(struct device *dev, const struct device_driver *drv)
>  	struct pci_dev *pci_dev = to_pci_dev(dev);
>  	struct pci_driver *pci_drv;
>  	const struct pci_device_id *found_id;
> +	struct pci_device_id id_copy;
>  
>  	if (pci_dev_binding_disallowed(pci_dev))
>  		return 0;
>  
>  	pci_drv = (struct pci_driver *)to_pci_driver(drv);
> -	found_id = pci_match_device(pci_drv, pci_dev);
> +	found_id = pci_match_device(pci_drv, pci_dev, &id_copy);
>  	if (found_id)
>  		return 1;
>  
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 64b308b6e61c..92c17c116de6 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -979,6 +979,7 @@ struct module;
>   *		function returns zero when the driver chooses to
>   *		take "ownership" of the device or an error code
>   *		(negative number) otherwise.
> + *		The pci_device_id parameter is only valid during probe.

The probe function takes a pointer to a struct pci_device_id, so I
think the requirement is that the struct pci_device_id only *needs* to
be valid during .probe(), right, i.e., the PCI core probe path makes
its own copy of the ID and doesn't retain the pointer after .probe()
returns, right?

I assume the caller determines the struct pci_device_id lifetime, and
it could be forever.

Could say something like:

  The pci_device_id parameter only needs to be valid during probe.

Thanks for doing this work; it should fix a subtle but important
issue.

>   *		The probe function always gets called from process
>   *		context, so it can sleep.
>   * @remove:	The remove() function gets called whenever a device
> 
> -- 
> 2.54.0
> 

  parent reply	other threads:[~2026-07-21 22:35 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-06 14:11 [PATCH v3 0/9] pci: fix UAF and TOCTOU related to dynamic ID Gary Guo
2026-07-06 14:11 ` [PATCH v3 1/9] ata: don't store pci_device_id Gary Guo
2026-07-07  1:12   ` Damien Le Moal
2026-07-07 14:12   ` sashiko-bot
2026-07-06 14:11 ` [PATCH v3 2/9] nsp32: " Gary Guo
2026-07-07 14:12   ` sashiko-bot
2026-07-06 14:11 ` [PATCH v3 3/9] ipack: tpci200: " Gary Guo
2026-07-07 14:12   ` sashiko-bot
2026-07-06 14:11 ` [PATCH v3 4/9] mlxsw: " Gary Guo
2026-07-07 14:12   ` sashiko-bot
2026-07-06 14:11 ` [PATCH v3 5/9] agp/via: don't rely on address of pci_device_id Gary Guo
2026-07-07 14:12   ` sashiko-bot
2026-07-06 14:11 ` [PATCH v3 6/9] agp/amd-k7: " Gary Guo
2026-07-07 14:12   ` sashiko-bot
2026-07-06 14:11 ` [PATCH v3 7/9] pci: make pci_match_one_device match on ID instead of device Gary Guo
2026-07-07 14:12   ` sashiko-bot
2026-07-21 22:33   ` Bjorn Helgaas
2026-07-06 14:11 ` [PATCH v3 8/9] pci: fix dyn_id add TOCTOU Gary Guo
2026-07-07 14:12   ` sashiko-bot
2026-07-21 22:34   ` Bjorn Helgaas
2026-07-06 14:11 ` [PATCH v3 9/9] pci: fix UAF when probe runs concurrent to dyn ID removal Gary Guo
2026-07-07 14:12   ` sashiko-bot
2026-07-21 22:35   ` Bjorn Helgaas [this message]
2026-07-23 18:57     ` Gary Guo
2026-07-23 19:29       ` Bjorn Helgaas
2026-07-23 19:42         ` Bjorn Helgaas
2026-07-23 19:44         ` Gary Guo
2026-07-23 21:10           ` Bjorn Helgaas
2026-07-21 13:17 ` [PATCH v3 0/9] pci: fix UAF and TOCTOU related to dynamic ID Gary Guo
2026-07-23 21:21 ` Danilo Krummrich

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=20260721223500.GA690676@bhelgaas \
    --to=helgaas@kernel.org \
    --cc=James.Bottomley@hansenpartnership.com \
    --cc=airlied@redhat.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=bhelgaas@google.com \
    --cc=cassel@kernel.org \
    --cc=dakr@kernel.org \
    --cc=davem@davemloft.net \
    --cc=dlemoal@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=driver-core@lists.linux.dev \
    --cc=edumazet@google.com \
    --cc=gary@garyguo.net \
    --cc=gotom@debian.or.jp \
    --cc=gregkh@linuxfoundation.org \
    --cc=idosch@nvidia.com \
    --cc=industrypack-devel@lists.sourceforge.net \
    --cc=jens.taprogge@taprogge.org \
    --cc=kuba@kernel.org \
    --cc=linux-ide@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=martin.petersen@oracle.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=petrm@nvidia.com \
    --cc=rafael@kernel.org \
    --cc=sashiko-bot@kernel.org \
    --cc=vaibhavgupta40@gmail.com \
    --cc=yokota@netlab.is.tsukuba.ac.jp \
    --cc=zhenzhong.duan@gmail.com \
    /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.