From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id DA8211FF0AB for ; Wed, 09 Sep 2026 16:53:42 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 4D6F621645; Wed, 09 Sep 2026 16:53:29 +0200 (CEST) From: Fiona Ebner To: pve-devel@lists.proxmox.com Subject: [PATCH qemu v2 3/7] add more stable fixes for QEMU 11.1.1 Date: Wed, 9 Sep 2026 16:52:13 +0200 Message-ID: <20260909145252.454610-4-f.ebner@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260909145252.454610-1-f.ebner@proxmox.com> References: <20260909145252.454610-1-f.ebner@proxmox.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1788965567732 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.552 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) KAM_LOTSOFHASH 0.25 Emails with lots of hash-like gibberish RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: I5WKH3WOCXFUDD57B22COFCLLVEMWWBG X-Message-ID-Hash: I5WKH3WOCXFUDD57B22COFCLLVEMWWBG X-MailFrom: f.ebner@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Cherry pick from upstream master: - vga display: fix possible OOB write - scsi: fix possible OOB read - vapic: fix potential memory region overlap - socket iochannel: correctly handle zero-length write Signed-off-by: Fiona Ebner --- New in v2. ...ix-text-mode-OOB-write-after-a-graph.patch | 164 ++++++++++++++++++ ...-fix-out-of-bound-read-in-WRITE-SAME.patch | 71 ++++++++ ...ELECT-block-size-change-behind-a-qui.patch | 89 ++++++++++ ...-the-VAPIC-region-to-0xc0000.0xe0000.patch | 75 ++++++++ ...-MemoryRegion-if-vapic_map_rom_writa.patch | 36 ++++ ...t-do-not-treat-a-zero-length-write-a.patch | 54 ++++++ debian/patches/series | 6 + 7 files changed, 495 insertions(+) create mode 100644 debian/patches/extra/0006-hw-display-vga-fix-text-mode-OOB-write-after-a-graph.patch create mode 100644 debian/patches/extra/0007-scsi-disk-fix-out-of-bound-read-in-WRITE-SAME.patch create mode 100644 debian/patches/extra/0008-scsi-hide-MODE-SELECT-block-size-change-behind-a-qui.patch create mode 100644 debian/patches/extra/0009-vapic-confine-the-VAPIC-region-to-0xc0000.0xe0000.patch create mode 100644 debian/patches/extra/0010-i386-vapic-unref-MemoryRegion-if-vapic_map_rom_writa.patch create mode 100644 debian/patches/extra/0011-io-channel-socket-do-not-treat-a-zero-length-write-a.patch diff --git a/debian/patches/extra/0006-hw-display-vga-fix-text-mode-OOB-write-after-a-graph.patch b/debian/patches/extra/0006-hw-display-vga-fix-text-mode-OOB-write-after-a-graph.patch new file mode 100644 index 0000000000..9c7c7f6d32 --- /dev/null +++ b/debian/patches/extra/0006-hw-display-vga-fix-text-mode-OOB-write-after-a-graph.patch @@ -0,0 +1,164 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warisjeet Singh +Date: Mon, 24 Aug 2026 12:47:26 -0400 +Subject: [PATCH] hw/display/vga: fix text-mode OOB write after a graphics + surface switch + +vga_draw_text() decides whether the console surface needs a resize from +its geometry cache, but none of the cache terms observe the graphics +renderer having replaced the console surface in between: + +- last_width/last_height are shared with vga_draw_graphic(), which + stores them in pixels while the text path stores characters; +- last_depth stays 0 for legacy (non-VBE) graphics modes, because + vga_get_bpp() only reports a depth when VBE is enabled, so the + "s->last_depth" term that normally forces a resize after a graphics + frame does not fire. + +So a graphics frame that shrinks the console surface (e.g. 80x25 +pixels) followed by a text frame with matching character geometry +(80x25 chars) skips the resize, and the glyph loop then paints +width*cw x height*cheight pixels into the smaller surface, out of +bounds, with guest-controlled (DAC palette) values, on every display +refresh. + +Separate the geometry cache per renderer: text paths (vga_draw_text, +vga_update_text, and the text handling in vga_invalidate_display / +vga_common_reset) now only manipulate last_text_{width,height}, in +characters; last_{width,height} become graphics-only, in pixels. +Additionally, make the text path compare the pixel size it is about +to paint against the console surface's actual dimensions. The +surface check is the load-bearing term: caches in either unit cannot +see the other renderer swapping the surface, the surface can. + +Fixes: CVE-2026-77913 +Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4215 +Cc: qemu-stable@nongnu.org +Signed-off-by: Warisjeet Singh (sin99xx) +Message-ID: +(cherry picked from commit 418396be8013386a81f8d8d89ac0effcf03a64b6) +Signed-off-by: Fiona Ebner +--- + hw/display/vga.c | 37 ++++++++++++++++++++++--------------- + hw/display/vga_int.h | 3 ++- + 2 files changed, 24 insertions(+), 16 deletions(-) + +diff --git a/hw/display/vga.c b/hw/display/vga.c +index da0c331486..cb0e28b79b 100644 +--- a/hw/display/vga.c ++++ b/hw/display/vga.c +@@ -1241,7 +1241,10 @@ static void vga_draw_text(VGACommonState *s, int full_update) + return; + } + +- if (width != s->last_width || height != s->last_height || ++ if (surface == NULL || ++ surface_width(surface) != width * cw || ++ surface_height(surface) != height * cheight || ++ width != s->last_text_width || height != s->last_text_height || + cw != s->last_cw || cheight != s->last_ch || s->last_depth) { + s->last_scr_width = width * cw; + s->last_scr_height = height * cheight; +@@ -1249,8 +1252,8 @@ static void vga_draw_text(VGACommonState *s, int full_update) + surface = qemu_console_surface(s->con); + qemu_console_text_resize(s->con, width, height); + s->last_depth = 0; +- s->last_width = width; +- s->last_height = height; ++ s->last_text_width = width; ++ s->last_text_height = height; + s->last_ch = cheight; + s->last_cw = cw; + full_update = 1; +@@ -1845,6 +1848,8 @@ static void vga_invalidate_display(void *opaque) + + s->last_width = -1; + s->last_height = -1; ++ s->last_text_width = -1; ++ s->last_text_height = -1; + } + + void vga_common_reset(VGACommonState *s) +@@ -1887,6 +1892,8 @@ void vga_common_reset(VGACommonState *s) + s->last_ch = 0; + s->last_width = 0; + s->last_height = 0; ++ s->last_text_width = 0; ++ s->last_text_height = 0; + s->last_scr_width = 0; + s->last_scr_height = 0; + s->cursor_start = 0; +@@ -1938,8 +1945,8 @@ static void vga_update_text(void *opaque, uint32_t *chardata) + s->graphic_mode = graphic_mode; + full_update = 1; + } +- if (s->last_width == -1) { +- s->last_width = 0; ++ if (s->last_text_width == -1) { ++ s->last_text_width = 0; + full_update = 1; + } + +@@ -1978,15 +1985,15 @@ static void vga_update_text(void *opaque, uint32_t *chardata) + break; + } + +- if (width != s->last_width || height != s->last_height || ++ if (width != s->last_text_width || height != s->last_text_height || + cw != s->last_cw || cheight != s->last_ch) { + s->last_scr_width = width * cw; + s->last_scr_height = height * cheight; + qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height); + qemu_console_text_resize(s->con, width, height); + s->last_depth = 0; +- s->last_width = width; +- s->last_height = height; ++ s->last_text_width = width; ++ s->last_text_height = height; + s->last_ch = cheight; + s->last_cw = cw; + full_update = 1; +@@ -2071,22 +2078,22 @@ static void vga_update_text(void *opaque, uint32_t *chardata) + } + + /* Display a message */ +- s->last_width = 60; +- s->last_height = height = 3; ++ s->last_text_width = 60; ++ s->last_text_height = height = 3; + qemu_console_text_set_cursor(s->con, -1, -1); +- qemu_console_text_resize(s->con, s->last_width, height); ++ qemu_console_text_resize(s->con, s->last_text_width, height); + +- for (dst = chardata, i = 0; i < s->last_width * height; i ++) ++ for (dst = chardata, i = 0; i < s->last_text_width * height; i ++) + *dst++ = ' '; + + size = strlen(msg_buffer); +- width = (s->last_width - size) / 2; +- dst = chardata + s->last_width + width; ++ width = (s->last_text_width - size) / 2; ++ dst = chardata + s->last_text_width + width; + for (i = 0; i < size; i ++) + *dst++ = ATTR2CHTYPE(msg_buffer[i], QEMU_COLOR_BLUE, + QEMU_COLOR_BLACK, 1); + +- qemu_console_text_update(s->con, 0, 0, s->last_width, height); ++ qemu_console_text_update(s->con, 0, 0, s->last_text_width, height); + } + + static uint64_t vga_mem_read(void *opaque, hwaddr addr, +diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h +index 5664317ecd..ca69ae9815 100644 +--- a/hw/display/vga_int.h ++++ b/hw/display/vga_int.h +@@ -122,7 +122,8 @@ typedef struct VGACommonState { + uint32_t plane_updated; + uint32_t last_line_offset; + uint8_t last_cw, last_ch; +- uint32_t last_width, last_height; /* in chars or pixels */ ++ uint32_t last_width, last_height; /* in pixels (graphics renderer) */ ++ uint32_t last_text_width, last_text_height; /* in chars (text renderer) */ + uint32_t last_scr_width, last_scr_height; /* in pixels */ + uint32_t last_depth; /* in bits */ + bool last_byteswap; diff --git a/debian/patches/extra/0007-scsi-disk-fix-out-of-bound-read-in-WRITE-SAME.patch b/debian/patches/extra/0007-scsi-disk-fix-out-of-bound-read-in-WRITE-SAME.patch new file mode 100644 index 0000000000..ffab5481da --- /dev/null +++ b/debian/patches/extra/0007-scsi-disk-fix-out-of-bound-read-in-WRITE-SAME.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 26 Aug 2026 19:22:41 +0200 +Subject: [PATCH] scsi-disk: fix out-of-bound read in WRITE SAME + +A guest with an attached scsi-hd can force QEMU's SCSI disk emulation +to read roughly 60 KiB past the end of a heap buffer, copying that out +of bounds host memory into the guest's own disk image. + +WRITE SAME computes the request transfer length at dev->blocksize +when the request is prepared and sets cmd->xfer from dev->blocksize. +scsi_disk_emulate_command() then uses cmd->xfer as the size of the +request buffer. + +However, MODE SELECT can race with the WRITE SAME command and guest raise +the logical block size to any value whose low bits fit 0xfe00, up to 65024. +In the presence of this race, scsi_disk_emulate_write_same() will read +from memory as many bytes as indicated by the *new* dev->blocksize, +and write it to disk. + +The read length in WRITE SAME must be bounded by the buffer that was +actually allocated, not by the mutable s->qdev.blocksize, so clamp the +length used against inbuf to r->buflen. Re-validating req->cmd.xfer +against the current block size would not work because the race is +intrinsic in the SCSI protocol. + +I am not sure if this is exploitable with virtio-scsi and other SG-capable +HBAs, because it should process the WRITE SAME input immediately, +without letting the MODE SELECT command race with it. + +Fixes: 356c4c441ec ("scsi-disk: allow MODE SELECT block descriptor to set the block size", 2022-07-13) +Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4365 +Cc: qemu-stable@nongnu.org +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Paolo Bonzini +(cherry picked from commit d30254aec93141d6b89262986a62764b2ae07177) +Signed-off-by: Fiona Ebner +--- + hw/scsi/scsi-disk.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index 1b0cce128c..5bb7a974d6 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -1911,6 +1911,7 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf) + SCSIRequest *req = &r->req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + uint32_t nb_sectors = scsi_data_cdb_xfer(r->req.cmd.buf); ++ uint32_t buflen = MIN(s->qdev.blocksize, r->buflen); + WriteSameCBData *data; + uint8_t *buf; + int i, l; +@@ -1930,7 +1931,7 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf) + return; + } + +- if ((req->cmd.buf[1] & 0x1) || buffer_is_zero(inbuf, s->qdev.blocksize)) { ++ if ((req->cmd.buf[1] & 0x1) || buffer_is_zero(inbuf, buflen)) { + int flags = (req->cmd.buf[1] & 0x8) ? BDRV_REQ_MAY_UNMAP : 0; + + /* The request is used as the AIO opaque value, so add a ref. */ +@@ -1956,7 +1957,7 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf) + qemu_iovec_init_external(&data->qiov, &data->iov, 1); + + for (i = 0; i < data->iov.iov_len; i += l) { +- l = MIN(s->qdev.blocksize, data->iov.iov_len - i); ++ l = MIN(buflen, data->iov.iov_len - i); + memcpy(&buf[i], inbuf, l); + } + diff --git a/debian/patches/extra/0008-scsi-hide-MODE-SELECT-block-size-change-behind-a-qui.patch b/debian/patches/extra/0008-scsi-hide-MODE-SELECT-block-size-change-behind-a-qui.patch new file mode 100644 index 0000000000..28b60a97d2 --- /dev/null +++ b/debian/patches/extra/0008-scsi-hide-MODE-SELECT-block-size-change-behind-a-qui.patch @@ -0,0 +1,89 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 26 Aug 2026 19:53:31 +0200 +Subject: [PATCH] scsi: hide MODE SELECT block size change behind a quirk + +This is a dangerous operation in that the block size is not +protected by a lock, but it can be written concurrently if +you have a multi-queue virtio-scsi HBA. Put it behind a quirk +that is only enabled by the Q800 machine, since the MODE +SELECT feature was added for A/UX. + +Cc: qemu-stable@nongnu.org +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Paolo Bonzini +(cherry picked from commit 0f410adf6b0dead1f09938054da639954bda3bc1) +Signed-off-by: Fiona Ebner +--- + hw/m68k/q800.c | 2 ++ + hw/scsi/scsi-disk.c | 12 ++++++++++-- + include/hw/scsi/scsi.h | 1 + + 3 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c +index ab64250c47..1ad3f93b29 100644 +--- a/hw/m68k/q800.c ++++ b/hw/m68k/q800.c +@@ -710,12 +710,14 @@ static void q800_init(Object *obj) + + static GlobalProperty hw_compat_q800[] = { + { "scsi-hd", "quirk_mode_page_vendor_specific_apple", "on" }, ++ { "scsi-hd", "quirk_mode_page_set_block_size", "on" }, + { "scsi-hd", "vendor", " SEAGATE" }, + { "scsi-hd", "product", " ST225N" }, + { "scsi-hd", "ver", "1.0 " }, + { "scsi-cd", "quirk_mode_page_apple_vendor", "on" }, + { "scsi-cd", "quirk_mode_sense_rom_use_dbd", "on" }, + { "scsi-cd", "quirk_mode_page_vendor_specific_apple", "on" }, ++ { "scsi-cd", "quirk_mode_page_set_block_size", "on" }, + { "scsi-cd", "quirk_mode_page_truncated", "on" }, + { "scsi-cd", "vendor", "MATSHITA" }, + { "scsi-cd", "product", "CD-ROM CR-8005" }, +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index 5bb7a974d6..a42f7d8e77 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -1673,8 +1673,12 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) + goto invalid_param; + } + +- /* Allow changing the block size */ +- if (bd_len) { ++ /* ++ * Allow changing the block size only if the quirk is enabled for it. ++ * Writing s->qdev.blocksize is not thread safe! ++ */ ++ if (bd_len && (s->quirks & ++ (1 << SCSI_DISK_QUIRK_MODE_PAGE_SET_BLOCK_SIZE))) { + bs = p[5] << 16 | p[6] << 8 | p[7]; + + /* +@@ -3247,6 +3251,8 @@ static const Property scsi_hd_properties[] = { + DEFINE_PROP_BIT("quirk_mode_page_vendor_specific_apple", SCSIDiskState, + quirks, SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE, + 0), ++ DEFINE_PROP_BIT("quirk_mode_page_set_block_size", SCSIDiskState, ++ quirks, SCSI_DISK_QUIRK_MODE_PAGE_SET_BLOCK_SIZE, 0), + DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf), + }; + +@@ -3352,6 +3358,8 @@ static const Property scsi_cd_properties[] = { + 0), + DEFINE_PROP_BIT("quirk_mode_page_truncated", SCSIDiskState, quirks, + SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED, 0), ++ DEFINE_PROP_BIT("quirk_mode_page_set_block_size", SCSIDiskState, ++ quirks, SCSI_DISK_QUIRK_MODE_PAGE_SET_BLOCK_SIZE, 0), + }; + + static void scsi_cd_class_initfn(ObjectClass *klass, const void *data) +diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h +index c60c6e8810..3eab339b0d 100644 +--- a/include/hw/scsi/scsi.h ++++ b/include/hw/scsi/scsi.h +@@ -262,5 +262,6 @@ bool scsi_generic_pr_state_preempt(SCSIDevice *s, Error **errp); + #define SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD 1 + #define SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE 2 + #define SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED 3 ++#define SCSI_DISK_QUIRK_MODE_PAGE_SET_BLOCK_SIZE 4 + + #endif diff --git a/debian/patches/extra/0009-vapic-confine-the-VAPIC-region-to-0xc0000.0xe0000.patch b/debian/patches/extra/0009-vapic-confine-the-VAPIC-region-to-0xc0000.0xe0000.patch new file mode 100644 index 0000000000..c0b17c6339 --- /dev/null +++ b/debian/patches/extra/0009-vapic-confine-the-VAPIC-region-to-0xc0000.0xe0000.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 26 Aug 2026 20:02:56 +0200 +Subject: [PATCH] vapic: confine the VAPIC region to 0xc0000..0xe0000 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The VAPIC region is mapped as writable RAM, at very high priority, +above existing memory. If the guest is allowed to map it everywhere, +it can overlap PCI BARs or even SMRAM. Ensure that the whole +region first in the 128K of low memory that are reserved to +option ROMs. + +Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4206 +Reported-by: Artem Dinaburg +Cc: qemu-stable@nongnu.org +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Paolo Bonzini +(cherry picked from commit d61c8a6fb7388486353aa267ba0d75b098f16662) +Signed-off-by: Fiona Ebner +--- + hw/i386/vapic.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/hw/i386/vapic.c b/hw/i386/vapic.c +index 8dd9188d96..9adce17262 100644 +--- a/hw/i386/vapic.c ++++ b/hw/i386/vapic.c +@@ -34,6 +34,10 @@ + #define ROM_BLOCK_SIZE 512 + #define ROM_BLOCK_MASK (~(ROM_BLOCK_SIZE - 1)) + ++/* Option ROM window on PC/Q35 machines; the vapic ROM must live in here. */ ++#define OPTION_ROM_START 0xc0000 ++#define OPTION_ROM_END 0xe0000 ++ + typedef enum VAPICMode { + VAPIC_INACTIVE = 0, + VAPIC_ACTIVE = 1, +@@ -592,6 +596,14 @@ static int vapic_map_rom_writable(VAPICROMState *s) + size_t rom_size; + uint8_t *ram; + ++ /* ++ * The VAPIC region should be mapped in place, refuse mapping it ++ * outside of the option ROM window. ++ */ ++ if (rom_paddr < OPTION_ROM_START || rom_paddr >= OPTION_ROM_END) { ++ return -1; ++ } ++ + if (s->rom_mapped_writable) { + memory_region_del_subregion(mr, &s->rom); + object_unparent(OBJECT(&s->rom)); +@@ -606,9 +618,10 @@ static int vapic_map_rom_writable(VAPICROMState *s) + } + ram = memory_region_get_ram_ptr(section.mr); + rom_size = ram[rom_paddr + 2] * ROM_BLOCK_SIZE; +- if (rom_size == 0) { ++ if (rom_size == 0 || rom_size > OPTION_ROM_END - rom_paddr) { + return -1; + } ++ + s->rom_size = rom_size; + + /* We need to round to avoid creating subpages +@@ -616,6 +629,7 @@ static int vapic_map_rom_writable(VAPICROMState *s) + rom_size += rom_paddr & ~TARGET_PAGE_MASK; + rom_paddr &= TARGET_PAGE_MASK; + rom_size = TARGET_PAGE_ALIGN(rom_size); ++ assert(rom_paddr >= OPTION_ROM_START && rom_paddr + rom_size <= OPTION_ROM_END); + + memory_region_init_alias(&s->rom, OBJECT(s), "kvmvapic-rom", section.mr, + rom_paddr, rom_size); diff --git a/debian/patches/extra/0010-i386-vapic-unref-MemoryRegion-if-vapic_map_rom_writa.patch b/debian/patches/extra/0010-i386-vapic-unref-MemoryRegion-if-vapic_map_rom_writa.patch new file mode 100644 index 0000000000..c232e80930 --- /dev/null +++ b/debian/patches/extra/0010-i386-vapic-unref-MemoryRegion-if-vapic_map_rom_writa.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 26 Aug 2026 19:47:32 +0200 +Subject: [PATCH] i386/vapic: unref MemoryRegion if vapic_map_rom_writable + fails + +memory_region_find returns the memory region with an elevated +reference count. Drop the reference count also if the memory +region cannot be mapped writable. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Paolo Bonzini +(cherry picked from commit cfa6e2c52ca8f756461fe41f4ce40e61a82fd914) +Signed-off-by: Fiona Ebner +--- + hw/i386/vapic.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/i386/vapic.c b/hw/i386/vapic.c +index 9adce17262..5c3911cf9c 100644 +--- a/hw/i386/vapic.c ++++ b/hw/i386/vapic.c +@@ -614,11 +614,13 @@ static int vapic_map_rom_writable(VAPICROMState *s) + + /* read ROM size from RAM region */ + if (rom_paddr + 2 >= memory_region_size(section.mr)) { ++ memory_region_unref(section.mr); + return -1; + } + ram = memory_region_get_ram_ptr(section.mr); + rom_size = ram[rom_paddr + 2] * ROM_BLOCK_SIZE; + if (rom_size == 0 || rom_size > OPTION_ROM_END - rom_paddr) { ++ memory_region_unref(section.mr); + return -1; + } + diff --git a/debian/patches/extra/0011-io-channel-socket-do-not-treat-a-zero-length-write-a.patch b/debian/patches/extra/0011-io-channel-socket-do-not-treat-a-zero-length-write-a.patch new file mode 100644 index 0000000000..24834b364c --- /dev/null +++ b/debian/patches/extra/0011-io-channel-socket-do-not-treat-a-zero-length-write-a.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Denis V. Lunev" +Date: Mon, 31 Aug 2026 12:01:46 +0200 +Subject: [PATCH] io/channel-socket: do not treat a zero length write as an + error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +qio_channel_socket_writev() checks "ret <= 0" after sendmsg(). A zero +length iovec is written successfully and returns 0, so the success +falls into the errno switch, which acts on whatever the last failing +syscall left in errno. A stale EAGAIN turns it into +QIO_CHANNEL_ERR_BLOCK with errp untouched, and a caller which treats +every negative return as fatal then passes a NULL Error to +error_get_pretty(). The websocket handshake does exactly that, so an +unauthenticated client crashes QEMU during the greeting. + +Returning 0 is safe for callers which loop until everything is +written. qio_channel_writev_full_all() has no zero progress guard, but +iov_copy() yields no entries for a zero length write, so that loop is +never entered. A connected stream socket returns 0 only when there is +nothing to send. + +The WIN32 implementation in the same file uses "ret < 0". + +Fixes: CVE-2026-84788 +Fixes: 559607ea173a ("io: add QIOChannelSocket class") +Cc: qemu-stable@nongnu.org +Cc: Daniel P. Berrangé +Cc: Marc-André Lureau +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Marc-André Lureau +Signed-off-by: Denis V. Lunev +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit a3de21bfa5d0c33110942d407ff5c7903965d3ad) +Signed-off-by: Fiona Ebner +--- + io/channel-socket.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/io/channel-socket.c b/io/channel-socket.c +index 12773b832c..7920cee639 100644 +--- a/io/channel-socket.c ++++ b/io/channel-socket.c +@@ -667,7 +667,7 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, + + retry: + ret = sendmsg(sioc->fd, &msg, sflags); +- if (ret <= 0) { ++ if (ret < 0) { + switch (errno) { + case EAGAIN: + return QIO_CHANNEL_ERR_BLOCK; diff --git a/debian/patches/series b/debian/patches/series index fb7cf89ab3..3bc35489ec 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -3,6 +3,12 @@ extra/0002-fdmon-io_uring-avoid-idle-event-loop-being-accounted.patch extra/0003-block-vmdk-tolerate-known-seSparse-reserved1-bit.patch extra/0004-hw-display-qxl-validate-primary-surface-stride-again.patch extra/0005-hw-scsi-lsi53c895a-gracefully-handle-re-entrant-DMA.patch +extra/0006-hw-display-vga-fix-text-mode-OOB-write-after-a-graph.patch +extra/0007-scsi-disk-fix-out-of-bound-read-in-WRITE-SAME.patch +extra/0008-scsi-hide-MODE-SELECT-block-size-change-behind-a-qui.patch +extra/0009-vapic-confine-the-VAPIC-region-to-0xc0000.0xe0000.patch +extra/0010-i386-vapic-unref-MemoryRegion-if-vapic_map_rom_writa.patch +extra/0011-io-channel-socket-do-not-treat-a-zero-length-write-a.patch bitmap-mirror/0001-drive-mirror-add-support-for-sync-bitmap-mode-never.patch bitmap-mirror/0002-drive-mirror-add-support-for-conditional-and-always-.patch bitmap-mirror/0003-mirror-add-check-for-bitmap-mode-without-bitmap.patch -- 2.47.3