[SLOF] [PATCH slof] virtio-serial: Close device completely

Greg Kurz groug at kaod.org
Fri Mar 6 21:12:43 AEDT 2020


On Fri,  6 Mar 2020 15:39:33 +1100
Alexey Kardashevskiy <aik at ozlabs.ru> wrote:

> Linux closes stdout at the end of prom_init which triggers the FW quiesce
> code which closes the virtio-serial instance. This misses stopping
> the virtio queues, clearing the "emit" token and other things. However
> this seemed working for a little longer (until the Linux driver took over)
> till 0cdb2dd13c3e which moved the VQ descriptors around which caused
> use-after-free corruption.
> 
> This adds virtio_queue_term_vq(), cleanup in the forth driver, few checks
> and reverts emit to hvterm-emit.
> 
> Fixes: 0cdb2dd13c3e ("virtio: Store queue descriptors in virtio_device")

SHA1 is wrong.

https://git.qemu.org/?p=SLOF.git;a=commit;h=300384f3dc68588a051f5737aee3b5eab4dd19e4

> Signed-off-by: Alexey Kardashevskiy <aik at ozlabs.ru>
> ---
> 
> Turns out it is close(stdout) what triggers quiesce, not the client
> interface's "quiesce".
> 

Yeah I discovered that while trying to debug :)

> This helps with iommu_platform=off but iommu_platform=on still does not work.
> Debugging...
> 
> /home/aik/pbuild/qemu-localhost-ppc64/ppc64-softmmu/qemu-system-ppc64 \
> -device virtio-serial,id=virtio-serial0,iommu_platform=on,disable-modern=off,disable-legacy=on,ioeventfd=off \
> -nodefaults \
> -chardev stdio,id=STDIO0,signal=off,mux=on \
> -device virtconsole,id=virtconsole0,chardev=STDIO0 \
> -mon id=MON0,chardev=STDIO0,mode=readline \
> -nographic \
> -vga none \
> -machine pseries,cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken,cap-ccf-assist=off,ic-mode=xics \
> -m 2G \
> -smp 1 \
> -bios p/slof/boot_rom.bin \
> -enable-kvm \
> -initrd t/le.cpio \
> -kernel t/vml4120le \
> -L /home/aik/t/qemu-ppc64-bios/ \
> -trace events=qemu_trace_events \
> -d guest_errors \
> -chardev socket,id=SOCKET0,server,nowait,path=qemu.mon.ssh55056 \
> -mon chardev=SOCKET0,mode=control
> 
> 
> ---
>  lib/libvirtio/virtio-serial.c    |  7 +++++++
>  board-qemu/slof/virtio-serial.fs | 11 ++++++++++-
>  2 files changed, 17 insertions(+), 1 deletion(-)
> 
> diff --git a/lib/libvirtio/virtio-serial.c b/lib/libvirtio/virtio-serial.c
> index d1503a44f433..92afb02014b2 100644
> --- a/lib/libvirtio/virtio-serial.c
> +++ b/lib/libvirtio/virtio-serial.c
> @@ -102,6 +102,10 @@ void virtio_serial_shutdown(struct virtio_device *dev)
>  	/* Quiesce device */
>  	virtio_set_status(dev, VIRTIO_STAT_FAILED);
>  
> +	/* Stop queues */
> +	virtio_queue_term_vq(dev, &dev->vq[TX_Q], TX_Q);
> +	virtio_queue_term_vq(dev, &dev->vq[RX_Q], RX_Q);
> +

It is certainly appropriate to undo the effects of virtio_queue_init_vq()
when shutting down indeed, but according to the virtio 1 spec:

https://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html#x1-630001

=============================================================================
3.3.1 Driver Requirements: Device Cleanup

A driver MUST NOT alter descriptor table entries which have
been exposed in the available ring (and not marked consumed
by the device in the used ring) of a live virtqueue.

A driver MUST NOT decrement the available idx on a live
virtqueue (ie. there is no way to “unexpose” buffers).

Thus a driver MUST ensure a virtqueue isn’t live (by device reset)
before removing exposed buffers. 
=============================================================================

So I'm wondering if this should rather be done after virtio_reset_device(),
like virtionet_term() already does.

Also, shouldn't the other virtio drivers do the same ?

>  	/* Reset device */
>  	virtio_reset_device(dev);
>  }
> @@ -114,6 +118,9 @@ int virtio_serial_putchar(struct virtio_device *dev, char c)
>  	uint16_t last_used_idx, avail_idx;
>  	struct vqs *vq = &dev->vq[TX_Q];
>  
> +	if (!vq->desc)
> +		return 0;
> +
>  	avail_idx = virtio_modern16_to_cpu(dev, vq->avail->idx);
>  
>  	last_used_idx = vq->used->idx;
> diff --git a/board-qemu/slof/virtio-serial.fs b/board-qemu/slof/virtio-serial.fs
> index 42ab3e2ccc9c..5293ab1f6341 100644
> --- a/board-qemu/slof/virtio-serial.fs
> +++ b/board-qemu/slof/virtio-serial.fs
> @@ -25,6 +25,8 @@ virtio-setup-vd VALUE virtiodev
>              close-dev
>          THEN
>          FALSE to initialized?
> +	['] hvterm-emit to emit

Is it correct to assume hvterm-emit is the value we want to restore ?

Also the init function does:

    ['] virtio-serial-term-emit to emit
    ['] virtio-serial-term-key  to key
    ['] virtio-serial-term-key? to key?

Shouldn't we revert key and key? as well ?

> +	0 to virtiodev
>      THEN
>  ;
>  
> @@ -61,12 +63,18 @@ virtiodev virtio-serial-init drop
>  : close
>      open-count 0> IF
>          open-count 1 - dup to open-count
> -        0= IF close THEN
> +        0= IF
> +	    close
> +	    FALSE to initialized?
> +	    ['] hvterm-emit to emit
> +	    0 to virtiodev

Maybe f^wworth factoring this out to its own word ?

> +	THEN
>      THEN
>      close
>  ;
>  
>  : write ( addr len -- actual )
> +    virtiodev 0= IF nip EXIT THEN
>      tuck
>      0 ?DO
>          dup c@ virtiodev SWAP virtio-serial-putchar
> @@ -77,6 +85,7 @@ virtiodev virtio-serial-init drop
>  
>  : read ( addr len -- actual )
>      0= IF drop 0 EXIT THEN
> +    virtiodev 0= IF nip EXIT THEN
>      virtiodev virtio-serial-haschar 0= IF 0 swap c! -2 EXIT THEN
>      virtiodev virtio-serial-getchar swap c! 1
>  ;



More information about the SLOF mailing list