Linux SCSI subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Ruoyu Wang" <ruoyuw560@gmail.com>
Cc: linux-scsi@vger.kernel.org
Subject: Re: [PATCH] scsi: ch: publish changer devices after probe setup
Date: Wed, 17 Jun 2026 20:41:27 +0000	[thread overview]
Message-ID: <20260617204127.881C31F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260617182122.955546-1-ruoyuw560@gmail.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [High] Spurious udev open failures (Regression) due to deferred idr_replace().
- [Medium] Memory leak of the dynamically allocated `ch->dt` array in the `idr_replace()` error path.

Pre-existing issues:
- [Critical] Race condition between `ch_open()` and `ch_remove()` leads to a Use-After-Free of the `scsi_device` structure.
- [High] Information leak of uninitialized kernel heap memory in the `CHIOGELEM` ioctl handler.
--

commit 63eb67253a3c4a6ab60f598a1642027bbd386913
Author: Ruoyu Wang <ruoyuw560@gmail.com>

scsi: ch: publish changer devices after probe setup

ch_probe() inserts the new changer into ch_index_idr before initializing
the kref, lock and scsi_device pointer. ch_open() looks up the object
directly from the IDR by minor, so a racing open can observe a partially
initialized changer.

Reserve the minor with a NULL IDR entry, finish device setup and element
discovery, then publish the initialized changer with idr_replace().
Early opens continue to fail with -ENXIO until the object is ready.

> diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
> index 4010fdbf813cc..12061e4681ace 100644
> --- a/drivers/scsi/ch.c
> +++ b/drivers/scsi/ch.c

[ ... ]

> @@ -951,6 +952,15 @@ static int ch_probe(struct scsi_device *sd)
>  		ch_init_elem(ch);
>  
>  	mutex_unlock(&ch->lock);
> +
> +	spin_lock(&ch_index_lock);
> +	old = idr_replace(&ch_index_idr, ch, ch->minor);
> +	spin_unlock(&ch_index_lock);

[Severity: High]
Does this change introduce spurious udev open failures?

Looking at ch_probe(), device_create() is called earlier which emits a
KOBJ_ADD uevent, prompting udev to immediately create the device node and
attempt to open it.

Because idr_replace() is now deferred until here, ch_open() will observe a
NULL IDR entry during the udev open attempt and return -ENXIO. Since udev
rules do not automatically retry on -ENXIO, won't this permanently fail
userspace device initialization, whereas previously it would gracefully
block on mutex_lock(&ch->lock)?

> +	if (IS_ERR(old)) {
> +		ret = PTR_ERR(old);
> +		goto destroy_dev;

[Severity: Medium]
Does this error path leak the ch->dt array?

If idr_replace() fails, we jump to destroy_dev and eventually to free_ch
where kfree(ch) is called directly. Since ch_readconfig(ch) was
successfully executed earlier in this function, it allocates the ch->dt
array. Does bypassing ch_destroy() leave the ch->dt array permanently
leaked?

> +	}
> +
>  	dev_set_drvdata(dev, ch);
>  	sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);

[ ... ]

[Severity: Critical]
This is a pre-existing issue, but can a race condition between ch_open()
and ch_remove() lead to a use-after-free of the scsi_device structure?

In ch_open(), after the ch structure is found via the IDR and its kref is
incremented, the ch_index_lock is released:

ch_open() {
    ...
    ch = idr_find(&ch_index_idr, minor);
    if (ch == NULL || !kref_get_unless_zero(&ch->ref)) {
        spin_unlock(&ch_index_lock);
        return -ENXIO;
    }
    spin_unlock(&ch_index_lock);
    if (scsi_device_get(ch->device)) {
    ...
}

Concurrently, if a device removal occurs, ch_remove() drops the driver's
reference to the scsi_device:

ch_remove() {
    ...
    scsi_device_put(ch->device);
    kref_put(&ch->ref, ch_destroy);
    ...
}

If this drops the final reference to the scsi_device, it can be freed
before the preempted ch_open() resumes and calls
scsi_device_get(ch->device). Could this be triggered by userspace
repeatedly opening the device while it is being hot-unplugged?

[Severity: High]
This is a pre-existing issue, but does the CHIOGELEM ioctl leak
uninitialized kernel heap memory to userspace?

The CHIOGELEM ioctl allocates a buffer using kmalloc() without the
__GFP_ZERO flag:

ch_ioctl() {
    ...
    buffer = kmalloc(512, GFP_KERNEL);
    ...
    result = ch_do_scsi(ch, ch_cmd, 12, buffer, 256, REQ_OP_DRV_IN);
    ...
    memcpy(cge.cge_pvoltag,buffer+28,36);
    ...
    if (copy_to_user(argp, &cge, sizeof (cge)))
    ...
}

If the SCSI device returns a short read, the trailing bytes of the buffer
retain uninitialized kernel heap memory. The driver then copies from this
buffer into the cge structure and calls copy_to_user(). Can this leak up
to 72 bytes of potentially sensitive uninitialized memory to userspace?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260617182122.955546-1-ruoyuw560@gmail.com?part=1

      reply	other threads:[~2026-06-17 20:41 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-17 18:21 [PATCH] scsi: ch: publish changer devices after probe setup Ruoyu Wang
2026-06-17 20:41 ` sashiko-bot [this message]

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=20260617204127.881C31F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=ruoyuw560@gmail.com \
    --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