All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Phil Pemberton" <philpem@philpem.me.uk>
Cc: cassel@kernel.org, linux-scsi@vger.kernel.org,
	dlemoal@kernel.org, linux-ide@vger.kernel.org
Subject: Re: [PATCH v9 07/11] ata: libata-scsi: convert dev->sdev to per-LUN array
Date: Tue, 06 Oct 2026 23:58:47 +0000	[thread overview]
Message-ID: <sashiko-outbox-162543@kernel.org> (raw)
In-Reply-To: <20261006234202.1139018-8-philpem@philpem.me.uk>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] ata: UAF in ata_acpi_uevent() accessing freed scsi_device kobject
- [Medium] of: memory leak in ata_scsi_assign_ofnode() due to missing of_node_put()
- [Medium] ata: libata-zpodd: stale from_notify flag in zpodd_wake_dev() causes unintended tray ejection
- [Medium] ata: redundant scsi_resume_device() calls on already-resumed LUNs due to shared device flag
--

commit 6719cc4aa927e2dd12a61aea767af00a2eb99075
Author: Phil Pemberton <philpem@philpem.me.uk>

ata: libata-scsi: convert dev->sdev to per-LUN array

Multi-LUN ATAPI devices share one ata_device and expose several SCSI
devices. Replace dev->sdev with an eight-slot array indexed by LUN and
update its callers. Single-LUN devices use slot 0; unused slots are NULL.

> diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
> index 4433f626246ba..2d1662f6f0642 100644
> --- a/drivers/ata/libata-acpi.c
> +++ b/drivers/ata/libata-acpi.c
> @@ -153,10 +153,13 @@ static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
>  	char *envp[] = { event_string, NULL };
>  
>  	if (dev) {
> -		if (dev->sdev)
> -			kobj = &dev->sdev->sdev_gendev.kobj;
> -	} else
> +		struct scsi_device *sdev = ata_dev_scsi_device(dev, 0);
> +
> +		if (sdev)
> +			kobj = &sdev->sdev_gendev.kobj;

[Severity: High]
Is this scsi_device kobject safe from being freed during this call?

The scsi_device is retrieved via ata_dev_scsi_device() without taking
ap->lock or acquiring a reference with scsi_device_get(). A concurrent
unplug could drop the reference count and free the device object before
kobject_uevent_env() executes, leading to a use-after-free.

> +	} else {
>  		kobj = &ap->dev->kobj;
> +	}
>  
>  	if (kobj) {

[ ... ]

> diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
> index 3131d84204ed7..68d6ca1f791dd 100644
> --- a/drivers/ata/libata-scsi.c
> +++ b/drivers/ata/libata-scsi.c

[ ... ]

> @@ -5259,9 +5270,9 @@ int ata_scsi_add_hosts(struct ata_host *host, const struct scsi_host_template *s
>  }
>  
>  #ifdef CONFIG_OF
> -static void ata_scsi_assign_ofnode(struct ata_device *dev, struct ata_port *ap)
> +static void ata_scsi_assign_ofnode(struct scsi_device *sdev,
> +				   struct ata_device *dev, struct ata_port *ap)
>  {

[Severity: Medium]
Does ata_scsi_assign_ofnode() leak a device tree node reference?

When for_each_available_child_of_node() inside this function finds a
matching port, it assigns the child to sdev->sdev_gendev.of_node and
returns early. The iterator implicitly acquires a reference to the child
node on each iteration. Since the SCSI and driver cores do not
automatically call of_node_put() on the device of_node during teardown,
this leaves a persistent reference leak.

> -	struct scsi_device *sdev = dev->sdev;
>  	struct device *d = ap->host->dev;
>  	struct device_node *np = d->of_node;
>  	struct device_node *child;

[ ... ]

> @@ -5610,7 +5619,9 @@ void ata_scsi_dev_rescan(struct work_struct *work)
>  
>  	ata_for_each_link(link, ap, EDGE) {
>  		ata_for_each_dev(dev, link, ENABLED) {
> -			struct scsi_device *sdev = dev->sdev;
> +			struct scsi_device *sdevs[ATAPI_MAX_LUN] = {};
> +			bool retry = false;
> +			int lun, err;
>  
>  			/*
>  			 * If the port was suspended before this was scheduled,

[ ... ]

> -			spin_unlock_irqrestore(ap->lock, flags);
> -			if (do_resume) {
> -				ret = scsi_resume_device(sdev);
> -				if (ret == -EWOULDBLOCK) {
> -					scsi_device_put(sdev);
> -					goto unlock_scan;
> +			for (lun = 0; lun < ATAPI_MAX_LUN; lun++) {
> +				if (!sdevs[lun])
> +					continue;
> +
> +				spin_unlock_irqrestore(ap->lock, flags);
> +				if (do_resume) {
> +					err = scsi_resume_device(sdevs[lun]);
> +					if (err == -EWOULDBLOCK)
> +						goto put_sdev;
>  				}
> -				dev->flags &= ~ATA_DFLAG_RESUMING;
> +				err = scsi_rescan_device(sdevs[lun]);

[Severity: Medium]
Will this cause redundant resume attempts on already-resumed LUNs?

When do_resume is true, both scsi_resume_device() and scsi_rescan_device()
execute for every valid LUN without checking if that specific LUN was
already successfully resumed in a previous pass.

> +put_sdev:
> +				/* A deferred LUN must not prevent scanning its siblings. */
> +				if (err) {
> +					ret = err;
> +					retry = true;
> +				}
> +				scsi_device_put(sdevs[lun]);
> +				spin_lock_irqsave(ap->lock, flags);
>  			}
> -			ret = scsi_rescan_device(sdev);
> -			scsi_device_put(sdev);
> -			spin_lock_irqsave(ap->lock, flags);
>  
> -			if (ret)
> -				goto unlock_ap;
> +			if (do_resume && !retry)
> +				dev->flags &= ~ATA_DFLAG_RESUMING;

[Severity: Medium]
If any LUN sets retry to true by returning -EWOULDBLOCK, the per-device
ATA_DFLAG_RESUMING flag is kept set. Consequently, the next execution of
the workqueue will see do_resume as true and unconditionally re-resume all
sibling LUNs, even the ones that previously succeeded.

>  		}
>  	}

[ ... ]

> diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c
> index 581eb41ea0f3c..bbdcaaa357980 100644
> --- a/drivers/ata/libata-zpodd.c
> +++ b/drivers/ata/libata-zpodd.c

[ ... ]

> @@ -265,18 +272,21 @@ static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context)
>  {
>  	struct ata_device *ata_dev = context;
>  	struct zpodd *zpodd = ata_dev->zpodd;
> -	struct scsi_device *sdev;
> +	int lun;
>  
>  	if (event != ACPI_NOTIFY_DEVICE_WAKE)
>  		return;
> -	sdev = zpodd_get_sdev(ata_dev);
> -	if (!sdev)
> -		return;
> -	if (pm_runtime_suspended(&sdev->sdev_gendev)) {
> -		zpodd->from_notify = true;
> -		pm_runtime_resume(&sdev->sdev_gendev);
> +	for (lun = 0; lun < ATAPI_MAX_LUN; lun++) {
> +		struct scsi_device *sdev = zpodd_get_sdev(ata_dev, lun);
> +
> +		if (!sdev)
> +			continue;
> +		if (pm_runtime_suspended(&sdev->sdev_gendev)) {
> +			zpodd->from_notify = true;
> +			pm_runtime_resume(&sdev->sdev_gendev);
> +		}

[Severity: Medium]
Can the from_notify flag become stuck in a true state here?

Setting this per-ATA-device flag inside a per-LUN loop allows the flag to
be incorrectly left true. If the first suspended LUN causes an actual
resume, from_notify is set and then cleared in zpodd_post_poweron() when
EH runs. For subsequent suspended LUNs, from_notify is set to true again,
but pm_runtime_resume() finds the parent already active and does not
trigger EH. This leaves from_notify set to true, which will cause an
unintended physical tray ejection during the next power-on.

> +		scsi_device_put(sdev);
>  	}
> -	scsi_device_put(sdev);
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261006234202.1139018-1-philpem@philpem.me.uk?part=7

  reply	other threads:[~2026-10-06 23:58 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-06 23:41 [PATCH v9 00/11] ata: add multi-LUN support for ATAPI devices Phil Pemberton
2026-10-06 23:41 ` [PATCH v9 01/11] ata: libata-core: pin SCSI devices during port detach Phil Pemberton
2026-10-06 23:41 ` [PATCH v9 02/11] ata: libata-zpodd: reference SCSI devices in PM callbacks Phil Pemberton
2026-10-06 23:59   ` sashiko-bot
2026-10-06 23:41 ` [PATCH v9 03/11] scsi: scsi_devinfo: preserve full-width quirk identifiers Phil Pemberton
2026-10-06 23:41 ` [PATCH v9 04/11] scsi: sr: initialize logical block size before registering the disk Phil Pemberton
2026-10-06 23:53   ` sashiko-bot
2026-10-06 23:41 ` [PATCH v9 05/11] scsi: sr: retry unfinished media revalidation on the next open Phil Pemberton
2026-10-06 23:52   ` sashiko-bot
2026-10-06 23:41 ` [PATCH v9 06/11] ata: libata-scsi: add atapi_max_lun module parameter Phil Pemberton
2026-10-06 23:41 ` [PATCH v9 07/11] ata: libata-scsi: convert dev->sdev to per-LUN array Phil Pemberton
2026-10-06 23:58   ` sashiko-bot [this message]
2026-10-07  2:38     ` Phil Pemberton
2026-10-06 23:41 ` [PATCH v9 08/11] ata: libata-scsi: route non-zero LUN commands for multi-LUN ATAPI Phil Pemberton
2026-10-06 23:41 ` [PATCH v9 09/11] scsi: add BLIST_NO_LUN_1F blacklist flag Phil Pemberton
2026-10-06 23:42 ` [PATCH v9 10/11] ata: libata-scsi: probe additional LUNs for multi-LUN ATAPI devices Phil Pemberton
2026-10-06 23:42 ` [PATCH v9 11/11] scsi: scsi_devinfo: add COMPAQ PD-1 multi-LUN ATAPI device quirk Phil Pemberton

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-162543@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=cassel@kernel.org \
    --cc=dlemoal@kernel.org \
    --cc=linux-ide@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=philpem@philpem.me.uk \
    --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.