Kernel KVM virtualization development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Eric Farman" <farman@linux.ibm.com>
Cc: kvm@vger.kernel.org, linux-s390@vger.kernel.org,
	"Heiko Carstens" <hca@linux.ibm.com>,
	"Vasily Gorbik" <gor@linux.ibm.com>,
	"Alexander Gordeev" <agordeev@linux.ibm.com>
Subject: Re: [PATCH v6 10/10] s390/vfio_ccw: implement a crw lock
Date: Sun, 26 Jul 2026 17:39:00 +0000	[thread overview]
Message-ID: <20260726173901.48D311F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260726172153.1818056-11-farman@linux.ibm.com>

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

Pre-existing issues:
- [High] A race condition between asynchronous channel path events (vfio_ccw_chp_event) and device removal (vfio_ccw_mdev_remove) can cause a Use-After-Free of the private structure.
- [High] Unbounded growth of the CRW queue leads to kernel memory leaks and potential OOM.
- [High] Unsynchronized replacement and freeing of eventfd triggers in vfio_ccw_mdev_set_irqs races with their usage, leading to a Use-After-Free.
- [High] Incorrect teardown sequence in vfio_ccw_mdev_release_dev frees list elements before cancelling asynchronous work, causing a memory leak or UAF.
- [Medium] A 0-byte read operation on the CRW region inappropriately consumes and drops a CRW event.
--

--- Patch [10]: [PATCH v6 10/10] s390/vfio_ccw: implement a crw lock ---
commit a24849c415dabc5f49c5f9509d897bea1c9a72dc
Author: Eric Farman <farman@linux.ibm.com>

s390/vfio_ccw: implement a crw lock

Unlike the channel_program struct, which covers synchronous I/O
submissions and asynchronous interrupts, the CRW region relies
exclusively on asynchronous events coming from hardware.
Implement a lock to manage the list of those payloads, to ensure
they are read cohesively.

> diff --git a/drivers/s390/cio/vfio_ccw_chp.c b/drivers/s390/cio/vfio_ccw_chp.c
> index f3015132d4b5f..7708eb4d6de0b 100644
> --- a/drivers/s390/cio/vfio_ccw_chp.c
> +++ b/drivers/s390/cio/vfio_ccw_chp.c
[ ... ]
> @@ -113,6 +108,16 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
>  	i = array_index_nospec(i, private->num_regions);
>  	region = private->region[i].data;
>  
> +	spin_lock_irqsave(&private->crw_lock, flags);
> +	crw = list_first_entry_or_null(&private->crw,
> +				       struct vfio_ccw_crw, next);
> +
> +	if (crw)
> +		list_del(&crw->next);
> +
> +	/* Drop CRW lock while copying to userspace */
> +	spin_unlock_irqrestore(&private->crw_lock, flags);
> +

[Severity: Medium]
This is a pre-existing issue, but does a 0-byte read operation on the CRW
region inappropriately consume and drop a CRW event?

If userspace performs a read operation on the CRW region with count == 0, the
driver proceeds to dequeue an event from private->crw here, performs a 0-byte
copy_to_user(), and then frees the CRW object. The event would be lost forever
without being delivered.

> diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
> index faf2de074a10f..d7e93b9d491ca 100644
> --- a/drivers/s390/cio/vfio_ccw_drv.c
> +++ b/drivers/s390/cio/vfio_ccw_drv.c
> @@ -122,11 +122,14 @@ void vfio_ccw_sch_io_todo(struct work_struct *work)
>  void vfio_ccw_crw_todo(struct work_struct *work)
>  {
>  	struct vfio_ccw_private *private;
> +	unsigned long flags;
>  
>  	private = container_of(work, struct vfio_ccw_private, crw_work);
>  
> +	spin_lock_irqsave(&private->crw_lock, flags);
>  	if (!list_empty(&private->crw) && private->crw_trigger)
>  		eventfd_signal(private->crw_trigger);
> +	spin_unlock_irqrestore(&private->crw_lock, flags);
>  }

[Severity: High]
This is a pre-existing issue, but is there an unsynchronized replacement and
freeing of eventfd triggers in vfio_ccw_mdev_set_irqs() that races with their
usage here?

Userspace can call the VFIO_DEVICE_SET_IRQS ioctl to change or clear eventfds.
vfio_ccw_mdev_set_irqs() handles this and calls eventfd_ctx_put() without
holding any locks to serialize it against asynchronous readers like
vfio_ccw_crw_todo().

If a reader holds a pointer to private->crw_trigger while the ioctl drops the
reference, could the reader call eventfd_signal() on a freed object?

> @@ -296,7 +300,9 @@ static void vfio_ccw_queue_crw(struct vfio_ccw_private *private,
>  	crw->crw.erc = erc;
>  	crw->crw.rsid = rsid;
>  
> +	spin_lock_irqsave(&private->crw_lock, flags);
>  	list_add_tail(&crw->next, &private->crw);
> +	spin_unlock_irqrestore(&private->crw_lock, flags);
>  	queue_work(vfio_ccw_work_q, &private->crw_work);
>  }

[Severity: High]
This is a pre-existing issue, but could unbounded growth of the CRW queue
lead to kernel memory leaks and potential OOM?

vfio_ccw_queue_crw() unconditionally allocates new struct vfio_ccw_crw objects
using kzalloc_obj(GFP_ATOMIC) and appends them to private->crw. Without bounds
checking or a limit on the number of elements, a stream of events could cause
the queue to grow infinitely, consuming un-reclaimable kernel memory.

[Severity: High]
This is a pre-existing issue, but is there a race condition between
asynchronous channel path events and device removal?

In vfio_ccw_chp_event(), the private structure is fetched using
dev_get_drvdata() without acquiring a reference count:

vfio_ccw_chp_event()
    struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);

Concurrently, if a user unbinds the device, vfio_ccw_mdev_remove() executes,
clearing the drvdata and dropping the final reference via vfio_put_device(),
which frees the private structure.

Could vfio_ccw_chp_event() then call vfio_ccw_queue_crw(), dereferencing the
freed pointer and causing a Use-After-Free?

> diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
> index ddfcd2b4296f1..2f28846fdf724 100644
> --- a/drivers/s390/cio/vfio_ccw_ops.c
> +++ b/drivers/s390/cio/vfio_ccw_ops.c
[ ... ]
> @@ -137,11 +138,14 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
>  	struct vfio_ccw_private *private =
>  		container_of(vdev, struct vfio_ccw_private, vdev);
>  	struct vfio_ccw_crw *crw, *temp;
> +	unsigned long flags;
>  
> +	spin_lock_irqsave(&private->crw_lock, flags);
>  	list_for_each_entry_safe(crw, temp, &private->crw, next) {
>  		list_del(&crw->next);
>  		kfree(crw);
>  	}
> +	spin_unlock_irqrestore(&private->crw_lock, flags);
>  
>  	/* Should be empty, but just in case */
>  	cancel_work_sync(&private->io_work);

[Severity: High]
This is a pre-existing issue, but does this teardown sequence free list
elements before cancelling asynchronous work?

By iterating through private->crw and freeing all elements before calling
cancel_work_sync(&private->crw_work), the lifecycle ordering violates the
principle of stopping asynchronous work before freeing the resources it
operates on.

If an event concurrently calls vfio_ccw_queue_crw() and inserts an element
after the list is emptied but before cancel_work_sync(), could the element
be leaked?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260726172153.1818056-1-farman@linux.ibm.com?part=10

      reply	other threads:[~2026-07-26 17:39 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-26 17:21 [PATCH v6 00/10] s390/vfio_ccw fixes Eric Farman
2026-07-26 17:21 ` [PATCH v6 01/10] s390/vfio_ccw: free all memory if cp_init() fails Eric Farman
2026-07-26 17:34   ` sashiko-bot
2026-07-26 17:21 ` [PATCH v6 02/10] s390/vfio_ccw: limit the number of channel program segments Eric Farman
2026-07-26 17:32   ` sashiko-bot
2026-07-26 17:21 ` [PATCH v6 03/10] s390/vfio_ccw: fix out of bounds check on CCW array Eric Farman
2026-07-26 17:27   ` sashiko-bot
2026-07-26 17:21 ` [PATCH v6 04/10] s390/vfio_ccw: ensure first IDAW remains constant Eric Farman
2026-07-26 17:40   ` sashiko-bot
2026-07-26 17:21 ` [PATCH v6 05/10] s390/vfio_ccw: calculate idal length based on idaw type Eric Farman
2026-07-26 17:36   ` sashiko-bot
2026-07-26 17:21 ` [PATCH v6 06/10] s390/vfio_ccw: ensure index for read/write regions are within range Eric Farman
2026-07-26 17:38   ` sashiko-bot
2026-07-26 17:21 ` [PATCH v6 07/10] s390/vfio_ccw: cancel existing workqueues Eric Farman
2026-07-26 17:38   ` sashiko-bot
2026-07-26 17:21 ` [PATCH v6 08/10] s390/vfio_ccw: move cp cleanup out of not operational Eric Farman
2026-07-26 17:40   ` sashiko-bot
2026-07-26 17:21 ` [PATCH v6 09/10] s390/vfio_ccw: implement a channel program mutex Eric Farman
2026-07-26 17:40   ` sashiko-bot
2026-07-26 17:21 ` [PATCH v6 10/10] s390/vfio_ccw: implement a crw lock Eric Farman
2026-07-26 17:39   ` 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=20260726173901.48D311F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=agordeev@linux.ibm.com \
    --cc=farman@linux.ibm.com \
    --cc=gor@linux.ibm.com \
    --cc=hca@linux.ibm.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-s390@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