Virtuozzo QEMU development (svt-core@virtuozzo.com)
 help / color / mirror / Atom feed
From: no-reply@sashiko.virtuozzo.com
To: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>,
	 svt-core@virtuozzo.com
Subject: Re: [PATCH QEMU HCI-8.1 v6 22/34] kvm: tolerate ioctls after kvm_close()
Date: Mon, 2 Nov 2026 11:01:26 +0000	[thread overview]
Message-ID: <010701a19bebd5eb-0e4bbf9e-7640-49ee-9287-bf896e982cd6-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261102-vfio_v1-v6-22-9bc7cabc850d@virtuozzo.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] kvm: ioctl wrappers return 0 after kvm_close(), faking fd 0 for fd-returning ioctls
- [Medium] kvm: closed-state ioctl guard returns 0 for fd-returning ioctls, handing out fd 0
- [Low] kvm: stale fds left in kvm_parked_vcpus after kvm_close() now stay reachable
--

commit d8d6e98a861f3d1c2b3dafd0181c053060a2ea99
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 descriptors are closed. The goal 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]
kvm_close() runs cpu_remove_sync() for each CPU, which reaches
do_kvm_destroy_vcpu() and then kvm_park_vcpu(). That stores the vCPU fd
number in kvm_state->kvm_parked_vcpus:

    vcpu->kvm_fd = cpu->kvm_fd;
    QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node);

kvm_close() then runs close(cpu->kvm_fd). Only cpu->kvm_fd is set to -1, and
the parked entry keeps the closed fd number.

Before this patch kvm_state was NULL after kvm_close(), so this list could not
be reached. With kvm_state kept alive, can kvm_create_vcpu() get a stale fd
from kvm_unpark_vcpu() on a vCPU hotplug after kvm_close()?

kvm_create_vcpu()
  kvm_fd = kvm_unpark_vcpu(s, vcpu_id);

kvm_init_vcpu() would then run mmap() and kvm_vcpu_ioctl() on that number.
The kvm_vcpu_ioctl() guard does not catch this, because kvm_create_vcpu()
has just assigned the stale value to cpu->kvm_fd. If the number has been
reused, an unrelated descriptor would be used.

If no parked entry matches, the new guard in kvm_vm_ioctl() returns 0 for
KVM_CREATE_VCPU:

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

Here 0 is accepted as the vCPU fd, so cpu->kvm_fd becomes 0.

The later patch in the series, "kvm: fix coalesced MMIO flush racing with
kvm_close()", only clears coalesced_mmio_ring and calls drain_call_rcu(). It
does not purge the parked list or guard kvm_unpark_vcpu().

[ ... ]

> @@ -3389,6 +3393,11 @@ int kvm_vm_ioctl(KVMState *s, unsigned long type, ...)
>      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 blanket return 0 hand out fd 0 to callers of ioctls that return a
new fd? Several of those callers only test for an error return, and the
argument structure is not filled in.

query_stats_cb() and query_stats_schemas_cb() only test for -1:

    stats_fd = kvm_vm_ioctl(s, KVM_GET_STATS_FD, NULL);
    if (stats_fd == -1) {
        ...
    }
    query_stats(result, target, names, stats_fd, NULL, errp);
    close(stats_fd);

After kvm_close(), a QMP query-stats or query-stats-schemas command gets
stats_fd == 0. The code then reads from fd 0 and calls close(0), which closes
stdin or whatever owns fd 0.

kvm_create_guest_memfd() tests only fd < 0:

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

A return of 0 is accepted there as a valid guest_memfd.

kvm_create_device() returns the unfilled field as a success:

    ret = kvm_vm_ioctl(s, KVM_CREATE_DEVICE, &create_dev);
    if (ret) {
        return ret;
    }
    return test ? 0 : create_dev.fd;

Here create_dev.fd is still -1.

In hw/vfio/helpers.c, vfio_kvm_device_add_fd() has a similar problem:

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

vfio_kvm_device_close() resets vfio_kvm_device_fd to -1, so this path is
taken again on a VFIO hot-add after kvm_close(). cd is initialised with only
.type, so cd.fd is 0 and vfio_kvm_device_fd becomes 0. Later ioctl() and
close() calls then act on stdin. It can be reached through
iommufd_cdev_kvm_device_add() -> vfio_kvm_device_add_fd().

The commit message gives the reason for returning 0 only for interrupt
injection, route commit and ioeventfd:

    Returning an error instead would still kill it: kvm_set_irq() aborts and
    kvm_irqchip_commit_routes() asserts on any failure, and the ioeventfd
    callers abort on a stale errno.

That reasoning does not cover the ioctls that return a descriptor. Should
those return a negative errno in the closed state, or should their callers
check for the closed state?

[ ... ]

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

[Severity: Medium]
Does this have the same problem for vCPU ioctls that return an fd?

kvm_init_vcpu() sets:

    cpu->kvm_vcpu_stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL);

If the vCPU fd is closed, this stores 0 as the stats fd.

The follow-up patches in the series change only kvm_close(). They add no
guard for any of these fd-returning callers.

-- 
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261102-vfio_v1-v6-0-9bc7cabc850d@virtuozzo.com?part=22

  reply	other threads:[~2026-11-02 11:01 UTC|newest]

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

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=010701a19bebd5eb-0e4bbf9e-7640-49ee-9287-bf896e982cd6-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