#1152521 trixie-pu: package qemu/1:10.0.15+ds-0+deb13u1

#1152521#5
Date:
2026-10-30 07:08:40 UTC
From:
To:
[ Reason ]
There's a new upstream stable/bugfix minor release, 10.0.15, fixing
a number of issues found since the previous stable release, including
multiple security issues, in particular:
 CVE-2026-111819 CVE-2026-7180 CVE-2026-97889 CVE-2026-101291
 CVE-2026-18410 CVE-2026-18204 CVE-2026-18609

[ Tests ]
This release, as all previous qemu stable releases, passes the upstream
testsuite on a variety of platforms (and many of the new changes comes
with a test verifying the issue exists before and is fixed after the
change).

Additionally, I booted a number of test virtual machines to see if
anything broke.  These are not good tests, just booting and a few basic
operations.

[ Risks ]
While the change between 10.0.14 and 10.0.15 is rather large, the bulk of
it are the changes to the testsuite.  Amount of changes is somewhat large
too, yet each fixes one particular issue, many of which were already faced
by users.  So the risk is rather small.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]
The list of changes is included in d/changelog as usual.
Additionally, actual list of upstream commits is available at

https://salsa.debian.org/qemu-team/qemu/-/commits/v10.0.15

and it might be easier to read/follow.

[ Other info ]
There's already a trixie-pu request for qemu, #1149847, for the
previous upstream stable/bugfix release, 10.0.14+ds-0+deb13u1.
This one is on top of that.

Thanks,

/mjt

diff -Nru qemu-10.0.14+ds/debian/changelog qemu-10.0.15+ds/debian/changelog
--- qemu-10.0.14+ds/debian/changelog	2026-10-03 20:01:57.000000000 +0300
+++ qemu-10.0.15+ds/debian/changelog	2026-10-29 20:44:29.000000000 +0300
@@ -1,3 +1,109 @@
+qemu (1:10.0.15+ds-0+deb13u1) trixie; urgency=medium
+
+  * new upstream stable/bugfix release, including multiple security fixes:
+   - Update version for 10.0.15 release
+   - target/ppc: Name the EBB exceptions
+   - hw/intc/exynos4210_combiner: Fix group register range check
+   - hw/intc/exynos4210_combiner: Avoid hw_error for guest errors
+   - hw/misc/bcm2835_cprman: Treat invalid clock mux source select as GND
+   - hw/usb/hcd-xhci: More reentrancy guard fixes for the XHCI code
+     (CVE-2026-111819)
+   - hw/usb/dev-mtp: Fix heap OOB read in usb_mtp_write_metadata()
+   - hw/usb/dev-mtp: Fix assert crash on short CMD_SEND_OBJECT
+   - usb-host: delete bottom halves during unrealize
+   - usb-host: free request on libusb submit failure
+   - tests/qtest/usb-hcd-xhci: test interrupt pacing above 2^32
+   - usb-host: free configuration descriptors on error paths
+   - usb-host: validate interface number before indexing altsetting
+   - tests/qtest: Cover OHCI endpoint type mismatches
+   - hw/usb/hcd-ohci: Fail iso packets sent to non-iso endpoints and vice-versa
+   - hw/usb/hcd-ohci: Assert isochronous TDs are never deferred
+     (two above commits: CVE-2026-7180)
+   - hw/usb/dev-mtp: Fix assert crash on undersized BULK IN
+   - hw/uefi: fix ContentInfo detection in wrap_pkcs7()
+   - hw/9pfs: fix dirent stream protection for legacy (9p2000.u) Tread
+   - iotests/migrate-bitmaps-postcopy-test: add a bitmap on a second node
+   - migration/block-dirty-bitmap: fix postcopy abort
+     with bitmaps on several nodes
+   - migration: add QEMU_COUNTED_STRING_SIZE for counted string buffers
+   - migration: fix qemu_get_counted_string annotation
+   - qemu-img: convert: flush target image after copying
+   - block: report flush error during bdrv_close()
+   - iotests.py: add filter_qemu()
+   - iotests: add test cases for failing flush after qemu-img convert
+   - seccomp: really fix blocking of setns/execveat/unshare
+   - seccomp: fix blocking of setns/execveat/unshare
+   - target/riscv: Check Svnapot PTE before updating A/D bits
+   - tests/qtest/bios-tables-test: Update riscv64 virt SPCR golden reference
+   - hw/riscv/virt-acpi-build: Fix the UART register width in SPCR
+   - tests/qtest/bios-tables-test: Allow changes to riscv64 virt SPCR
+   - target/riscv/kvm: Preserve FCSR across migration
+   - target/riscv: stop translating after WFI
+   - target/riscv: check G-stage write permission for VS-stage A/D updates
+   - tests/tcg/aarch64: Test the TTBR layout with TCR.DS and a 48-bit OA
+   - target/arm: Use the 52-bit TTBR base address layout when TCR.DS is set
+   - tests/tcg/aarch64: Add a test for a two-entry 52-bit TTBR table
+   - target/arm: Clear TTBR[5:0] from a 52-bit table base address
+   - tcg/riscv64: Remove vector min/max ops with immediates
+   - target/i386: fix immediate stack adjustment for RET and RETF
+   - target/i386/tcg: zero FXSAVE FOP and reserved slot bytes
+   - tests/tcg: Add tests for sign extension after rotate
+   - tcg/optimize: Do not derive s_mask from rotated s_mask
+   - hw/display/vga: fix OOB writes after external surface resize
+     (CVE-2026-97889)
+   - tpm_emulator: Reject sending commands smaller than the request header
+   - io: cork TLS writes to avoid small TLS records
+   - accel/kvm: coalesced mmio: check lenght of the MMIO write entry
+   - accel/kvm: Replace legacy cpu_physical_memory_write() call
+   - block: Remove now redundant bdrv_wait_serialising_requests() calls
+   - block: Fix corruption from broken RMW atomicity
+   - block: reject a reopen of an unusable node instead of crashing
+   - qcow2: do not clear the dirty bit when reopening a read-only node
+   - file-posix: add statx(STATX_DIOALIGN) support
+   - block: fix bdrv_next() skipping monitor-owned nodes
+   - iotests: cover inactivating a read-only node
+   - block/throttle-groups: fix crash when enabling I/O limits on a busy disk
+   - io: prevent unbounded read of websocket data from client
+     (CVE-2026-101291)
+   - hw/usb: Fix USB MTP Use-After-Free in usb_mtp_deletefn List Iteration
+   - target/i386/tcg: ignore VEX.L for unary scalar instructions
+   - accel/kvm: protect kvm_resample_fd_list with a mutex
+   - target/i386: Don't clear C1 for FCOMI/FCOMIP/FUCOMI/FUCOMIP
+   - target/i386: clear C1 for all x87 compare instructions
+   - target/i386/tcg: raise #GP(0) on null SS load with RPL != CPL
+   - hw/nvme: fix memory leak on sr-iov capable nvme controller removal
+   - hw/nvme: fix assertion failure on sr-iov capable nvme controller removal
+   - block/nbd: clear reply.cookie under receive_mutex
+   - block/nbd: never index requests[] with an unchecked cookie
+   - block/nbd: clear reply.cookie when the reply is rejected
+   - hw/display/qxl: trace skipped stale loadvm commands
+   - hw/display/qxl: validate replayed commands in qxl_post_load
+   - hw/display/qxl: factor out qxl_guest_phys2virt()
+   - hw/usb/dev-smartcard-reader: validate migrated fields in post_load
+   - hw/usb/dev-smartcard-reader: decode bulk-out length as little-endian
+   - hw/usb/dev-smartcard-reader: fix assert on pending answers overflow
+     (CVE-2026-18410)
+   - hw/usb/dev-smartcard-reader: fix OOB read from pending bulk-in ring
+     (CVE-2026-18204)
+   - hw/usb/dev-smartcard-reader: validate interrupt transfer length
+     (CVE-2026-18609)
+   - s390x/pci: Reject apertures beyond IOAT capacity in translation mode
+   - s390x/pci: Use qemu_log_mask() for guest-triggered errors in reg_ioat()
+   - s390x/pci: Fix frame stepping in rpcit_service_call()
+   - s390x/sclp: Reject short headers in PV case
+   - s390x/css: Use datastream pointer for checking no-data CCWs
+   - hw/intc/s390x: Fix check after g_try_realloc
+   - vfio/ap: Clear error object pointer after non-fatal errors
+   - virtio-ccw: Fix rc check in read configuration path
+   - virtio-ccw: Do not overwrite existing indicators
+   - virtio-ccw: Limit ISC to MAX_ISC
+   - hw/usb/hcd-xhci: Limit DMA transfers to plain memory
+   - target/arm: Fix WFxT timeouts when the offset puts the count ahead
+   - target/arm: Fix next timer tick when the offset puts the count ahead
+   - target/arm: Fix PMSAv8 shareability decode for R-profile MPU regions
+
+ -- Michael Tokarev <mjt@tls.msk.ru>  Thu, 29 Oct 2026 20:44:29 +0300
+
 qemu (1:10.0.14+ds-0+deb13u1) trixie; urgency=medium

   * new upstream stable/bugfix release, including multiple security fixes:
diff -Nru qemu-10.0.14+ds/debian/control.mk qemu-10.0.15+ds/debian/control.mk
--- qemu-10.0.14+ds/debian/control.mk	2026-10-03 20:01:57.000000000 +0300
+++ qemu-10.0.15+ds/debian/control.mk	2026-10-29 20:44:29.000000000 +0300
@@ -9,7 +9,7 @@

 # since some files and/or lists differ from version to version,
 # ensure we have the expected qemu version, or else scream loudly
-checked-version := 10.0.14+ds
+checked-version := 10.0.15+ds
 # version of last vdso change for d/control Depends field:
 vdso-version := 1:9.2.0~rc3+ds-1~

diff -Nru qemu-10.0.14+ds/VERSION qemu-10.0.15+ds/VERSION
--- qemu-10.0.14+ds/VERSION	2026-09-29 03:48:20.000000000 +0300
+++ qemu-10.0.15+ds/VERSION	2026-10-28 20:30:47.000000000 +0300
@@ -1 +1 @@
-10.0.14
+10.0.15
diff -Nru qemu-10.0.14+ds/accel/kvm/kvm-all.c qemu-10.0.15+ds/accel/kvm/kvm-all.c
--- qemu-10.0.14+ds/accel/kvm/kvm-all.c	2026-09-29 03:48:20.000000000 +0300
+++ qemu-10.0.15+ds/accel/kvm/kvm-all.c	2026-10-28 20:30:47.000000000 +0300
@@ -127,6 +127,7 @@
 static QLIST_HEAD(, KVMResampleFd) kvm_resample_fd_list =
     QLIST_HEAD_INITIALIZER(kvm_resample_fd_list);

+static QemuMutex kvm_resample_fd_list_lock;
 static QemuMutex kml_slots_lock;

 #define kvm_slots_lock()    qemu_mutex_lock(&kml_slots_lock)
@@ -138,6 +139,8 @@
 {
     KVMResampleFd *rfd;

+    qemu_mutex_lock(&kvm_resample_fd_list_lock);
+
     QLIST_FOREACH(rfd, &kvm_resample_fd_list, node) {
         if (rfd->gsi == gsi) {
             QLIST_REMOVE(rfd, node);
@@ -145,6 +148,8 @@
             break;
         }
     }
+
+    qemu_mutex_unlock(&kvm_resample_fd_list_lock);
 }

 static inline void kvm_resample_fd_insert(int gsi, EventNotifier *event)
@@ -154,20 +159,26 @@
     rfd->gsi = gsi;
     rfd->resample_event = event;

+    qemu_mutex_lock(&kvm_resample_fd_list_lock);
     QLIST_INSERT_HEAD(&kvm_resample_fd_list, rfd, node);
+    qemu_mutex_unlock(&kvm_resample_fd_list_lock);
 }

 void kvm_resample_fd_notify(int gsi)
 {
     KVMResampleFd *rfd;

+    qemu_mutex_lock(&kvm_resample_fd_list_lock);
+
     QLIST_FOREACH(rfd, &kvm_resample_fd_list, node) {
         if (rfd->gsi == gsi) {
             event_notifier_set(rfd->resample_event);
             trace_kvm_resample_fd_notify(gsi);
-            return;
+            break;
         }
     }
+
+    qemu_mutex_unlock(&kvm_resample_fd_list_lock);
 }

 /**
@@ -2572,6 +2583,7 @@
     int type;

     qemu_mutex_init(&kml_slots_lock);
+    qemu_mutex_init(&kvm_resample_fd_list_lock);

     s = KVM_STATE(ms->accelerator);

@@ -2839,16 +2851,18 @@
         struct kvm_coalesced_mmio_ring *ring = s->coalesced_mmio_ring;
         while (ring->first != ring->last) {
             struct kvm_coalesced_mmio *ent;
+            AddressSpace *as;

             ent = &ring->coalesced_mmio[ring->first];
-
-            if (ent->pio == 1) {
-                address_space_write(&address_space_io, ent->phys_addr,
-                                    MEMTXATTRS_UNSPECIFIED, ent->data,
-                                    ent->len);
+            if (ent->len > sizeof(ent->data)) {
+                warn_report("coalesced MMIO entry has invalid len %u",
+                            ent->len);
             } else {
-                cpu_physical_memory_write(ent->phys_addr, ent->data, ent->len);
+                as = ent->pio == 1 ? &address_space_io : &address_space_memory;
+                address_space_write(as, ent->phys_addr, MEMTXATTRS_UNSPECIFIED,
+                                    ent->data, ent->len);
             }
+
             smp_wmb();
             ring->first = (ring->first + 1) % KVM_COALESCED_MMIO_MAX;
         }
diff -Nru qemu-10.0.14+ds/backends/tpm/tpm_emulator.c qemu-10.0.15+ds/backends/tpm/tpm_emulator.c
--- qemu-10.0.14+ds/backends/tpm/tpm_emulator.c	2026-09-29 03:48:20.000000000 +0300
+++ qemu-10.0.15+ds/backends/tpm/tpm_emulator.c	2026-10-28 20:30:48.000000000 +0300
@@ -179,6 +179,11 @@
     ssize_t ret;
     bool is_selftest = false;

+    if (in_len < sizeof(struct tpm_req_hdr)) {
+        error_setg(errp, "tpm-emulator: invalid request size %u", in_len);
+        return -1;
+    }
+
     if (selftest_done) {
         *selftest_done = false;
         is_selftest = tpm_util_is_selftest(in, in_len);
diff -Nru qemu-10.0.14+ds/block/block-backend.c qemu-10.0.15+ds/block/block-backend.c
--- qemu-10.0.14+ds/block/block-backend.c	2026-09-29 03:48:20.000000000 +0300
+++ qemu-10.0.15+ds/block/block-backend.c	2026-10-28 20:30:48.000000000 +0300
@@ -625,6 +625,7 @@
             return bs;
         }
         it->phase = BDRV_NEXT_MONITOR_OWNED;
+        it->bs = NULL;
     }

     /* Then return the monitor-owned BDSes without a BB attached. Ignore all
@@ -1338,6 +1339,7 @@
                       QEMUIOVector *qiov, size_t qiov_offset,
                       BdrvRequestFlags flags)
 {
+    ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
     int ret;
     BlockDriverState *bs;
     IO_CODE();
@@ -1357,9 +1359,8 @@
     bdrv_inc_in_flight(bs);

     /* throttling disk I/O */
-    if (blk->public.throttle_group_member.throttle_state) {
-        throttle_group_co_io_limits_intercept(&blk->public.throttle_group_member,
-                bytes, THROTTLE_READ);
+    if (qatomic_load_acquire(&tgm->throttle_state)) {
+        throttle_group_co_io_limits_intercept(tgm, bytes, THROTTLE_READ);
     }

     ret = bdrv_co_preadv_part(blk->root, offset, bytes, qiov, qiov_offset,
@@ -1413,6 +1414,7 @@
                        QEMUIOVector *qiov, size_t qiov_offset,
                        BdrvRequestFlags flags)
 {
+    ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
     int ret;
     BlockDriverState *bs;
     IO_CODE();
@@ -1431,9 +1433,8 @@

     bdrv_inc_in_flight(bs);
     /* throttling disk I/O */
-    if (blk->public.throttle_group_member.throttle_state) {
-        throttle_group_co_io_limits_intercept(&blk->public.throttle_group_member,
-                bytes, THROTTLE_WRITE);
+    if (qatomic_load_acquire(&tgm->throttle_state)) {
+        throttle_group_co_io_limits_intercept(tgm, bytes, THROTTLE_WRITE);
     }

     if (!blk->enable_write_cache) {
diff -Nru qemu-10.0.14+ds/block/file-posix.c qemu-10.0.15+ds/block/file-posix.c
--- qemu-10.0.14+ds/block/file-posix.c	2026-09-29 03:48:20.000000000 +0300
+++ qemu-10.0.15+ds/block/file-posix.c	2026-10-28 20:30:48.000000000 +0300
@@ -410,28 +410,48 @@

     bs->bl.request_alignment = 0;
     s->buf_align = 0;
-    /* Let's try to use the logical blocksize for the alignment. */
-    if (probe_logical_blocksize(fd, &bs->bl.request_alignment) < 0) {
-        bs->bl.request_alignment = 0;
-    }

-#ifdef __linux__
+#if defined(__linux__) && defined(STATX_DIOALIGN)
+    struct statx stx;
+
     /*
-     * The XFS ioctl definitions are shipped in extra packages that might
-     * not always be available. Since we just need the XFS_IOC_DIOINFO ioctl
-     * here, we simply use our own definition instead:
+     * Linux 6.1 introduced an interface for both block devices and file
+     * systems. The system call returns with the STATX_DIOALIGN bit cleared
+     * when the information is unavailable.
      */
-    struct xfs_dioattr {
-        uint32_t d_mem;
-        uint32_t d_miniosz;
-        uint32_t d_maxiosz;
-    } da;
-    if (ioctl(fd, _IOR('X', 30, struct xfs_dioattr), &da) >= 0) {
-        bs->bl.request_alignment = da.d_miniosz;
-        /* The kernel returns wrong information for d_mem */
-        /* s->buf_align = da.d_mem; */
+    if (statx(fd, "", AT_EMPTY_PATH, STATX_DIOALIGN, &stx) == 0 &&
+        (stx.stx_mask & STATX_DIOALIGN)) {
+        bs->bl.request_alignment = stx.stx_dio_offset_align;
+        s->buf_align = stx.stx_dio_mem_align;
+    }
+#endif /* defined(__linux__) && defined(STATX_DIOALIGN) */
+
+#ifdef __linux__
+    if (!bs->bl.request_alignment) {
+        /*
+         * The XFS ioctl definitions are shipped in extra packages that might
+         * not always be available. Since we just need the XFS_IOC_DIOINFO ioctl
+         * here, we simply use our own definition instead:
+         */
+        struct xfs_dioattr {
+            uint32_t d_mem;
+            uint32_t d_miniosz;
+            uint32_t d_maxiosz;
+        } da;
+        if (ioctl(fd, _IOR('X', 30, struct xfs_dioattr), &da) >= 0) {
+            bs->bl.request_alignment = da.d_miniosz;
+            /* The kernel returns wrong information for d_mem */
+            /* s->buf_align = da.d_mem; */
+        }
+    }
+#endif /* __linux__ */
+
+    /* Let's try to use the logical blocksize for the alignment. */
+    if (!bs->bl.request_alignment) {
+        if (probe_logical_blocksize(fd, &bs->bl.request_alignment) < 0) {
+            bs->bl.request_alignment = 0;
+        }
     }
-#endif

     /*
      * If we could not get the sizes so far, we can only guess them. First try
diff -Nru qemu-10.0.14+ds/block/io.c qemu-10.0.15+ds/block/io.c
--- qemu-10.0.14+ds/block/io.c	2026-09-29 03:48:20.000000000 +0300
+++ qemu-10.0.15+ds/block/io.c	2026-10-28 20:30:48.000000000 +0300
@@ -48,6 +48,9 @@
 static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
     int64_t offset, int64_t bytes, BdrvRequestFlags flags);

+static void coroutine_fn
+bdrv_wait_serialising_requests_locked(BdrvTrackedRequest *self);
+
 static void GRAPH_RDLOCK
 bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
 {
@@ -618,6 +621,7 @@
         .type           = type,
         .co             = qemu_coroutine_self(),
         .serialising    = false,
+        .active_owner   = false,
         .overlap_offset = offset,
         .overlap_bytes  = bytes,
     };
@@ -626,6 +630,15 @@

     qemu_mutex_lock(&bs->reqs_lock);
     QLIST_INSERT_HEAD(&bs->tracked_requests, req, list);
+
+    /*
+     * Set .waiting_for while we're holding the lock, otherwise we'd open a race
+     * window where another request in the middle of its RMW cycle starts
+     * waiting for us, leading to potential data corruption if this request
+     * overwrites a block the RMW request has already read.
+     */
+    bdrv_wait_serialising_requests_locked(req);
+
     qemu_mutex_unlock(&bs->reqs_lock);
 }

@@ -686,6 +699,15 @@
     BdrvTrackedRequest *req;

     while ((req = bdrv_find_conflicting_request(self))) {
+        /*
+         * If this request is the active owner of the data blocks it accesses,
+         * no other conflicting request may exist; other requests have to wait
+         * for this one, not the other way around. If this condition is
+         * violated, RMW operations may be interrupted in the middle, operate on
+         * stale data and introduce data corruption.
+         */
+        assert(!self->active_owner);
+
         self->waiting_for = req;
         qemu_co_queue_wait(&req->wait_queue, &self->bs->reqs_lock);
         self->waiting_for = NULL;
@@ -784,20 +806,6 @@
     bdrv_wakeup(bs);
 }