mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] virtio_console: do not free control-out buffers on remove
@ 2026-08-18  5:47 Jia Jia
  2026-08-19  2:21 ` Jia Jia
  0 siblings, 1 reply; 2+ messages in thread
From: Jia Jia @ 2026-08-18  5:47 UTC (permalink / raw)
  To: amit, mst, jasowangio
  Cc: xuanzhuo, eperezma, gregkh, arnd, virtualization, linux-kernel, stable

__send_control_msg() publishes &portdev->cpkt as the control-out
virtqueue cookie. remove_vqs() walks every virtqueue and passes leftover
cookies to free_buf(), which treats them as struct port_buffer and
reads sgpages.

If a control message is still on c_ovq when the device is unbound,
free_buf() reads past the ports_device object.

KASAN reported the use through:

	free_buf
	remove_vqs
	virtcons_remove
	unbind_store

Drain c_ovq without freeing. The packet lives in portdev and is released
with it.

Fixes: a7a69ec0d8e4 ("virtio_console: free buffers after reset")
Cc: stable@vger.kernel.org
Signed-off-by: Jia Jia <physicalmtea@gmail.com>
---
 drivers/char/virtio_console.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 9a33217c68d9..6e9bf064826e 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1886,10 +1886,24 @@ static void remove_vqs(struct ports_device *portdev)
 
 	virtio_device_for_each_vq(portdev->vdev, vq) {
 		struct port_buffer *buf;
+		unsigned int len;
 
-		flush_bufs(vq, true);
-		while ((buf = virtqueue_detach_unused_buf(vq)))
-			free_buf(buf, true);
+		/*
+		 * c_ovq cookies are &portdev->cpkt, not port_buffer.
+		 * Detach them but do not free_buf().
+		 */
+		if (vq == portdev->c_ovq) {
+			spin_lock(&portdev->c_ovq_lock);
+			while (virtqueue_get_buf(vq, &len))
+				;
+			while (virtqueue_detach_unused_buf(vq))
+				;
+			spin_unlock(&portdev->c_ovq_lock);
+		} else {
+			flush_bufs(vq, true);
+			while ((buf = virtqueue_detach_unused_buf(vq)))
+				free_buf(buf, true);
+		}
 		cond_resched();
 	}
 	portdev->vdev->config->del_vqs(portdev->vdev);
-- 
2.34.1

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] virtio_console: do not free control-out buffers on remove
  2026-08-18  5:47 [PATCH] virtio_console: do not free control-out buffers on remove Jia Jia
@ 2026-08-19  2:21 ` Jia Jia
  0 siblings, 0 replies; 2+ messages in thread
From: Jia Jia @ 2026-08-19  2:21 UTC (permalink / raw)
  To: amit, mst, jasowangio
  Cc: xuanzhuo, eperezma, arnd, virtualization, linux-kernel, stable

>
> __send_control_msg() publishes &portdev->cpkt as the control-out
> virtqueue cookie. remove_vqs() walks every virtqueue and passes leftover
> cookies to free_buf(), which treats them as struct port_buffer and
> reads sgpages.
>
> If a control message is still on c_ovq when the device is unbound,
> free_buf() reads past the ports_device object.
>
> KASAN reported the use through:
>
>         free_buf
>         remove_vqs
>         virtcons_remove
>         unbind_store
>
> Drain c_ovq without freeing. The packet lives in portdev and is released
> with it.
>
> Fixes: a7a69ec0d8e4 ("virtio_console: free buffers after reset")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jia Jia <physicalmtea@gmail.com>
> ---
>  drivers/char/virtio_console.c | 20 +++++++++++++++++---
>  1 file changed, 17 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
> index 9a33217c68d9..6e9bf064826e 100644
> --- a/drivers/char/virtio_console.c
> +++ b/drivers/char/virtio_console.c
> @@ -1886,10 +1886,24 @@ static void remove_vqs(struct ports_device *portdev)
>
>         virtio_device_for_each_vq(portdev->vdev, vq) {
>                 struct port_buffer *buf;
> +               unsigned int len;
>
> -               flush_bufs(vq, true);
> -               while ((buf = virtqueue_detach_unused_buf(vq)))
> -                       free_buf(buf, true);
> +               /*
> +                * c_ovq cookies are &portdev->cpkt, not port_buffer.
> +                * Detach them but do not free_buf().
> +                */
> +               if (vq == portdev->c_ovq) {

The non-multiport case was not considered here; fixed in PATCH v2.

> +                       spin_lock(&portdev->c_ovq_lock);
> +                       while (virtqueue_get_buf(vq, &len))
> +                               ;
> +                       while (virtqueue_detach_unused_buf(vq))
> +                               ;
> +                       spin_unlock(&portdev->c_ovq_lock);
> +               } else {
> +                       flush_bufs(vq, true);
> +                       while ((buf = virtqueue_detach_unused_buf(vq)))
> +                               free_buf(buf, true);
> +               }
>                 cond_resched();
>         }
>         portdev->vdev->config->del_vqs(portdev->vdev);
> --
> 2.34.1

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-19  2:22 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-18  5:47 [PATCH] virtio_console: do not free control-out buffers on remove Jia Jia
2026-08-19  2:21 ` Jia Jia

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®