Virtuozzo QEMU development (svt-core@virtuozzo.com)
 help / color / mirror / Atom feed
From: no-reply@sashiko.virtuozzo.com
To: svt-core@virtuozzo.com,
	 Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
Cc: andrey.drobyshev@virtuozzo.com
Subject: Re: [PATCH QEMU HCI-8.1 v7 23/35] kvm: tolerate ioctls after kvm_close()
Date: Tue, 3 Nov 2026 14:21:20 +0000	[thread overview]
Message-ID: <010701a1a1c936da-43fc3a47-1f29-447a-863a-994b4a6dee45-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261103-vfio_v1-v7-23-4467fdccbbe6@virtuozzo.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Medium] kvm: kvm_vm_ioctl() returns 0 after kvm_close() for fd-returning ioctls, yielding fd 0
- [Medium] kvm: ioctl wrappers return 0 after kvm_close() without filling outputs
- [Medium] kvm: ioctl wrappers return 0 after kvm_close(), callers treat it as a valid fd
- [Low] kvm: closed-state checks in ioctl wrappers race with kvm_close()
--

commit e7e22762666ee0142be58442e3f90a44a9a53d12
Author: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>

kvm: tolerate ioctls after kvm_close()

This patch keeps kvm_state allocated after kvm_close() instead of setting
it to NULL. It makes kvm_ioctl(), kvm_vm_ioctl() and kvm_vcpu_ioctl()
return 0 once the file descriptors have been closed. The aim is to stop a
retired cpr-transfer source from crashing on late interrupts.

> diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
> --- a/accel/kvm/kvm-all.c
> +++ b/accel/kvm/kvm-all.c

[ ... ]

> @@ -644,7 +644,6 @@ void kvm_close(void)
>          close(kvm_state->fd);
>          kvm_state->fd = -1;
>      }
> -    kvm_state = NULL;
>  }

[Severity: Low]
Can the closed-state checks added below race with kvm_close()?

kvm_close() stores -1 into kvm_state->vmfd and kvm_state->fd with plain
stores after close(). It does not call accel_ioctl_inhibit_begin(), so it
does not wait for in-flight ioctls from threads that don't hold the BQL.

A thread without the BQL could pass the new s->vmfd == -1 test in
kvm_vm_ioctl(). kvm_close() could then close the descriptor. The first
thread would re-read s->vmfd for ioctl() and either get -EBADF or issue
the ioctl on a recycled descriptor number.

kvm_set_irq() and the ioeventfd callers treat that error as fatal. Is
there any synchronization that excludes this?

Also, kvm_enabled() and kvm_dirty_ring_enabled() keep reporting a live KVM
now that kvm_state is no longer set to NULL. Only the three ioctl wrappers
check for the closed state.

> @@ -3371,6 +3370,11 @@ int kvm_ioctl(KVMState *s, unsigned long type, ...)
>      arg = va_arg(ap, void *);
>      va_end(ap);
>  
> +    /* kvm_close() has been called: there is no KVM to talk to any more */
> +    if (s->fd == -1) {
> +        return 0;
> +    }
> +

[Severity: Medium]
Is returning 0 here safe for callers that read output from the ioctl?

This stub never writes the caller's output buffers or return value.
KVM_CHECK_EXTENSION, KVM_GET_VCPU_MMAP_SIZE and KVM_GET_SUPPORTED_* all
report success with no data. kvm_check_extension() would read the 0 as
"extension unsupported".

>      trace_kvm_ioctl(type, arg);
>      ret = ioctl(s->fd, type, arg);

[ ... ]

> @@ -3389,6 +3393,11 @@ int kvm_vm_ioctl(KVMState *s, unsigned long type, ...)
>      arg = va_arg(ap, void *);
>      va_end(ap);
>  
> +    /* kvm_close() has been called: there is no VM to talk to any more */
> +    if (s->vmfd == -1) {
> +        return 0;
> +    }
> +

[Severity: Medium]
Can this return 0 be mistaken for a valid file descriptor?

Several VM ioctls return a new fd as their result: KVM_GET_STATS_FD,
KVM_CREATE_GUEST_MEMFD, KVM_CREATE_VCPU and KVM_CREATE_DEVICE (through
cd.fd). After kvm_close() these now return 0, and the callers take that as
fd 0, which is stdin.

The most reachable case is query_stats_cb():

    stats_fd = kvm_vm_ioctl(s, KVM_GET_STATS_FD, NULL);
    if (stats_fd == -1) {
        error_setg_errno(errp, errno, "KVM stats: ioctl failed");
        return;
    }
    query_stats(result, target, names, stats_fd, NULL, errp);
    close(stats_fd);

The check for -1 passes, so a QMP query-stats reads from fd 0 and then
calls close(0). query_stats_schemas_cb() has the same pattern.

Other callers:

    kvm_create_guest_memfd():
        fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_GUEST_MEMFD, &guest_memfd);
        if (fd < 0) {

    kvm_create_vcpu():
        kvm_fd = kvm_vm_ioctl(s, KVM_CREATE_VCPU, vcpu_id);
        if (kvm_fd < 0) {

kvm_create_guest_memfd() accepts 0 as a guest_memfd. kvm_create_vcpu()
sets cpu->kvm_fd = 0.

In hw/vfio/helpers.c, vfio_kvm_device_add_fd() has this:

    if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
        ...
    }
    vfio_kvm_device_fd = cd.fd;

cd.fd is only initialised for .type, so it stays 0. vfio_kvm_device_fd
becomes 0, and a later vfio_kvm_device_close() calls close(0). It can also
be reached after vfio_kvm_device_close() has reset vfio_kvm_device_fd to
-1, because kvm_enabled() is still true after kvm_close().

openpic_kvm.c and s390_flic_kvm.c use cd.fd after a zero-initialised
KVM_CREATE_DEVICE call in the same way. kvm_create_device() sets
create_dev.fd = -1, but it would still return success with -1 as the fd.

Before this patch these calls dereferenced a NULL kvm_state. Should the
fd-returning requests return an error instead?

Also, for requests that fill an output struct, KVM_GET_CLOCK,
KVM_GET_IRQCHIP, KVM_GET_PIT2 and KVM_GET_DIRTY_LOG return success with
the buffer untouched. Can kvm_update_clock() in hw/i386/kvm/clock.c then
read data.clock from an uninitialised stack struct? Can kvm_pic_get() and
kvm_ioapic_get() copy uninitialised stack data into device state?
kvm_get_current_ns() in target/i386/kvm/xen-emu.c has the same pattern as
kvm_update_clock().

The commit message justifies the 0 only for the interrupt, irqfd and
ioeventfd callers. Does it cover callers that use the return value as a
handle or read the output buffer?

>      trace_kvm_vm_ioctl(type, arg);
>      accel_ioctl_begin();
>      ret = ioctl(s->vmfd, type, arg);

[ ... ]

> @@ -3409,6 +3418,11 @@ int kvm_vcpu_ioctl(CPUState *cpu, unsigned long type, ...)
>      arg = va_arg(ap, void *);
>      va_end(ap);
>  
> +    /* kvm_close() has been called: the vCPU fds are gone */
> +    if (cpu->kvm_fd == -1) {
> +        return 0;
> +    }
> +

[Severity: Medium]
Does the same issue apply to kvm_vcpu_ioctl()?

KVM_GET_STATS_FD on a closed vCPU returns 0, and kvm_init_vcpu() stores
that result in cpu->kvm_vcpu_stats_fd. The vCPU GET_* ioctls also return
success without writing any data. KVM_RUN returns without running.

If kvm_get_msrs() were reached through a stale CPUState, it would hit
assert(ret == nmsrs). cpu_remove_sync() takes the CPUs off CPU_FOREACH in
kvm_close(), so this is probably only reachable through a stale CPUState
pointer.

>      trace_kvm_vcpu_ioctl(cpu->cpu_index, type, arg);
>      accel_cpu_ioctl_begin(cpu);
>      ret = ioctl(cpu->kvm_fd, type, arg);

-- 
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261103-vfio_v1-v7-0-4467fdccbbe6@virtuozzo.com?part=23

  reply	other threads:[~2026-11-03 14:21 UTC|newest]

Thread overview: 72+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-03 13:57 [PATCH QEMU HCI-8.1 v7 00/35] vfio: support qemu-update with passed through GPU's and vGPU's #VSTOR-103860 Andrey Drobyshev
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 01/35] VZ: migration/cpr-exec: fix Error leak in preserve_ram() Andrey Drobyshev
2026-11-03 14:00   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 02/35] migration/cpr-exec: restore RAM write access if exec fails Andrey Drobyshev
2026-11-03 14:01   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 03/35] vfio/region: create BAR dma-bufs with O_CLOEXEC Andrey Drobyshev
2026-11-03 14:02   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 04/35] migration/cpr-exec: require a file or exec migration URI Andrey Drobyshev
2026-11-03 14:02   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 05/35] migration: close the CPR state if the outgoing channel fails to open Andrey Drobyshev
2026-11-03 14:03   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 06/35] migration/cpr-exec: close the persisted state if the " Andrey Drobyshev
2026-11-03 14:04   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 07/35] migration/cpr-exec: don't leak the dup'd memfd if g_setenv() fails Andrey Drobyshev
2026-11-03 14:04   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 08/35] migration: don't refuse a blocker over a migration of another mode Andrey Drobyshev
2026-11-03 14:05   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 09/35] migration: Plug memory leaks after migrate_set_error() Andrey Drobyshev
2026-11-03 14:05   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 10/35] hw/vfio: Fix liveness check in vfio_connect_kvm_msi_virq() Andrey Drobyshev
2026-11-03 14:05   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 11/35] vfio/pci: Reject invalid MSI-X Table and PBA BIR values Andrey Drobyshev
2026-11-03 14:05   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 12/35] vfio/pci: Fix information leak in vfio_rom_read() Andrey Drobyshev
2026-11-03 14:06   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 13/35] vfio/pci: Initialize rom_read_failed in vfio_pci_load_rom() Andrey Drobyshev
2026-11-03 14:06   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 14/35] vfio/pci: Grow buffer in vfio_pci_host_match() Andrey Drobyshev
2026-11-03 14:06   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 15/35] q35: Fix migration of SMRAM state Andrey Drobyshev
2026-11-03 14:08   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 16/35] migration: ensure APIC is loaded prior to VFIO PCI devices Andrey Drobyshev
2026-11-03 14:08   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 17/35] migration: Fix regression of passing error_fatal into vmstate_load_state() Andrey Drobyshev
2026-11-03 14:11   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 18/35] migration: vmstate_save_state_v: fix double error_setg Andrey Drobyshev
2026-11-03 14:11   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 19/35] migration: yank: Move register instance earlier Andrey Drobyshev
2026-11-03 14:16   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 20/35] migration: Free cpr-transfer MigrationAddress along with gsource Andrey Drobyshev
2026-11-03 14:14   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 21/35] migration: Move CPR HUP watch to cpr-transfer.c Andrey Drobyshev
2026-11-03 14:14   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 22/35] migration: Fix crash on second migration when cancel early Andrey Drobyshev
2026-11-03 14:16   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 23/35] kvm: tolerate ioctls after kvm_close() Andrey Drobyshev
2026-11-03 14:21   ` no-reply [this message]
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 24/35] kvm: fix coalesced MMIO flush racing with kvm_close() Andrey Drobyshev
2026-11-03 14:19   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 25/35] migration/cpr: add cpr_is_in_progress() Andrey Drobyshev
2026-11-03 14:21   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 26/35] vfio/migration: don't migrate device state during CPR Andrey Drobyshev
2026-11-03 14:26   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 27/35] vfio/migration: don't assume the device is running on CPR incoming Andrey Drobyshev
2026-11-03 14:25   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 28/35] migration/ram: don't start dirty logging in CPR modes Andrey Drobyshev
2026-11-03 14:27   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 29/35] VZ: vfio/cpr: don't close KVM on cpr-exec Andrey Drobyshev
2026-11-03 14:29   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 30/35] VZ: migration/cpr-exec: abort cpr-exec if memory can't be preserved Andrey Drobyshev
2026-11-03 14:29   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 31/35] VZ: migration/cpr-exec: take the vhost-net devices back if exec fails Andrey Drobyshev
2026-11-03 14:32   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 32/35] VZ: migration/cpr-exec: don't exec if a vhost-net device can't be released Andrey Drobyshev
2026-11-03 14:30   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 33/35] VZ: vfio/region: preserve BAR mappings across cpr-exec #VSTOR-103860 Andrey Drobyshev
2026-11-03 14:38   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 34/35] VZ: migration/cpr-exec: allow cpr-exec with VFIO devices #VSTOR-103860 Andrey Drobyshev
2026-11-03 14:33   ` no-reply
2026-11-03 13:57 ` [PATCH QEMU HCI-8.1 v7 35/35] VZ: vfio/migration: don't wait for stop-copy-only device state #VSTOR-141821 Andrey Drobyshev
2026-11-03 14:35   ` no-reply
2026-11-04 13:11 ` [PATCH QEMU HCI-8.1 v7 00/35] vfio: support qemu-update with passed through GPU's and vGPU's #VSTOR-103860 Denis V. Lunev

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=010701a1a1c936da-43fc3a47-1f29-447a-863a-994b4a6dee45-000000@eu-central-1.amazonses.com \
    --to=no-reply@sashiko.virtuozzo.com \
    --cc=andrey.drobyshev@virtuozzo.com \
    --cc=svt-core@virtuozzo.com \
    /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