* [PATCH 0/5] Various UI/security-related fixes
@ 2026-07-06 12:53 Marc-André Lureau
2026-07-06 12:53 ` [PATCH 1/5] i386/tdx: fix uninitialized variable warning in tdx_check_features Marc-André Lureau
` (4 more replies)
0 siblings, 5 replies; 13+ messages in thread
From: Marc-André Lureau @ 2026-07-06 12:53 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Marcelo Tosatti, kvm, Daniel P. Berrangé,
Marc-André Lureau
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
Marc-André Lureau (5):
i386/tdx: fix uninitialized variable warning in tdx_check_features
ui/vnc: fix OOB write in vnc_refresh_lossy_rect
ui/vnc: validate color shifts in SetPixelFormat
ui/vnc: use RFB wire types for client message handlers
ui/input-barrier: fix off-by-one in keycode bounds check
target/i386/kvm/tdx.c | 2 +-
ui/input-barrier.c | 2 +-
ui/vnc.c | 56 ++++++++++++++++++++++++++++++---------------------
3 files changed, 35 insertions(+), 25 deletions(-)
---
base-commit: 4ee536fac748b70e6f3d8568ddd20cfbaa9cf7bf
change-id: 20260706-fix-cca462e358c9
Best regards,
--
Marc-André Lureau <marcandre.lureau@redhat.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/5] i386/tdx: fix uninitialized variable warning in tdx_check_features
2026-07-06 12:53 [PATCH 0/5] Various UI/security-related fixes Marc-André Lureau
@ 2026-07-06 12:53 ` Marc-André Lureau
2026-07-13 11:12 ` Philippe Mathieu-Daudé
2026-07-06 12:53 ` [PATCH 2/5] ui/vnc: fix OOB write in vnc_refresh_lossy_rect Marc-André Lureau
` (3 subsequent siblings)
4 siblings, 1 reply; 13+ messages in thread
From: Marc-André Lureau @ 2026-07-06 12:53 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Marcelo Tosatti, kvm, Daniel P. Berrangé,
Marc-André Lureau
tdx_fetch_cpuid() only sets the output ret parameter on the error
path. GCC cannot prove that r is always initialized before use in
the caller, triggering -Werror=maybe-uninitialized.
Initialize r to -1 to silence the warning.
Fixes: 228e40f33048 ("i386/tdx: Fetch and validate CPUID of TD guest")
Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
---
target/i386/kvm/tdx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c
index c9c3b05d5fe..8294dbde3aa 100644
--- a/target/i386/kvm/tdx.c
+++ b/target/i386/kvm/tdx.c
@@ -887,7 +887,7 @@ static int tdx_check_features(X86ConfidentialGuest *cg, CPUState *cs)
FeatureWordInfo *wi;
FeatureWord w;
bool mismatch = false;
- int r;
+ int r = -1;
fetch_cpuid = tdx_fetch_cpuid(cs, &r);
if (!fetch_cpuid) {
--
2.55.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/5] ui/vnc: fix OOB write in vnc_refresh_lossy_rect
2026-07-06 12:53 [PATCH 0/5] Various UI/security-related fixes Marc-André Lureau
2026-07-06 12:53 ` [PATCH 1/5] i386/tdx: fix uninitialized variable warning in tdx_check_features Marc-André Lureau
@ 2026-07-06 12:53 ` Marc-André Lureau
2026-07-13 11:24 ` Philippe Mathieu-Daudé
2026-07-06 12:53 ` [PATCH 3/5] ui/vnc: validate color shifts in SetPixelFormat Marc-André Lureau
` (2 subsequent siblings)
4 siblings, 1 reply; 13+ messages in thread
From: Marc-André Lureau @ 2026-07-06 12:53 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Marcelo Tosatti, kvm, Daniel P. Berrangé,
Marc-André Lureau
vnc_refresh_lossy_rect() always marks a full VNC_STAT_RECT (64) rows
as dirty when refreshing a lossy tile. When the display height is not
a multiple of VNC_STAT_RECT (e.g. VNC_MAX_HEIGHT = 2160), the bottom
tile is partial -- the last tile at y=2112 has only 48 valid rows.
The unclamped loop writes to vs->dirty[2160..2175], past the end of
the VNC_MAX_HEIGHT-sized array.
Clamp the row count to the actual surface height so partial bottom
tiles only mark valid dirty bitmap entries.
Fixes: CVE-2026-48002
Fixes: 7d964c9d2fc6 ("vnc: refresh lossy rect after a given timeout")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3950
Reported-by: huntr bubble
Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
---
ui/vnc.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/ui/vnc.c b/ui/vnc.c
index b2b69923b75..559d3954b87 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3004,10 +3004,18 @@ static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
int sty = y / VNC_STAT_RECT;
int stx = x / VNC_STAT_RECT;
int has_dirty = 0;
+ int height = MIN(pixman_image_get_height(vd->guest.fb),
+ pixman_image_get_height(vd->server));
+ int rows;
y = QEMU_ALIGN_DOWN(y, VNC_STAT_RECT);
x = QEMU_ALIGN_DOWN(x, VNC_STAT_RECT);
+ rows = MIN(VNC_STAT_RECT, height - y);
+ if (rows <= 0) {
+ return 0;
+ }
+
QTAILQ_FOREACH(vs, &vd->clients, next) {
VncConnection *vc = container_of(vs, VncConnection, vs);
int j;
@@ -3022,7 +3030,7 @@ static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
}
vc->worker.lossy_rect[sty][stx] = 0;
- for (j = 0; j < VNC_STAT_RECT; ++j) {
+ for (j = 0; j < rows; ++j) {
bitmap_set(vs->dirty[y + j],
x / VNC_DIRTY_PIXELS_PER_BIT,
VNC_STAT_RECT / VNC_DIRTY_PIXELS_PER_BIT);
--
2.55.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/5] ui/vnc: validate color shifts in SetPixelFormat
2026-07-06 12:53 [PATCH 0/5] Various UI/security-related fixes Marc-André Lureau
2026-07-06 12:53 ` [PATCH 1/5] i386/tdx: fix uninitialized variable warning in tdx_check_features Marc-André Lureau
2026-07-06 12:53 ` [PATCH 2/5] ui/vnc: fix OOB write in vnc_refresh_lossy_rect Marc-André Lureau
@ 2026-07-06 12:53 ` Marc-André Lureau
2026-07-13 11:23 ` Philippe Mathieu-Daudé
2026-07-06 12:53 ` [PATCH 4/5] ui/vnc: use RFB wire types for client message handlers Marc-André Lureau
2026-07-06 12:53 ` [PATCH 5/5] ui/input-barrier: fix off-by-one in keycode bounds check Marc-André Lureau
4 siblings, 1 reply; 13+ messages in thread
From: Marc-André Lureau @ 2026-07-06 12:53 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Marcelo Tosatti, kvm, Daniel P. Berrangé,
Marc-André Lureau
A malicious VNC client can send a SetPixelFormat message with shift
values >= 32, causing UB mask computation
(e.g. red_max << red_shift where red_shift is 255). Apparently, this is
not covered by -fwrapv.
Reject color shifts >= bits_per_pixel before computing masks, and cast
the max values to uint32_t to avoid signed integer overflow when a
valid shift (e.g. 24) would set bit 31 of a signed int.
Fixes: 9f64916da20 ("pixman/vnc: use pixman images in vnc.")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3948
Reported-by: huntr bubble
Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
---
ui/vnc.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/ui/vnc.c b/ui/vnc.c
index 559d3954b87..94a38242c56 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2276,18 +2276,25 @@ static void set_pixel_format(VncState *vs, int bits_per_pixel,
return;
}
+ if (red_shift >= bits_per_pixel ||
+ green_shift >= bits_per_pixel ||
+ blue_shift >= bits_per_pixel) {
+ vnc_client_error(vs);
+ return;
+ }
+
vs->client_pf.rmax = red_max ? red_max : 0xFF;
vs->client_pf.rbits = ctpopl(red_max);
vs->client_pf.rshift = red_shift;
- vs->client_pf.rmask = red_max << red_shift;
+ vs->client_pf.rmask = (uint32_t)red_max << red_shift;
vs->client_pf.gmax = green_max ? green_max : 0xFF;
vs->client_pf.gbits = ctpopl(green_max);
vs->client_pf.gshift = green_shift;
- vs->client_pf.gmask = green_max << green_shift;
+ vs->client_pf.gmask = (uint32_t)green_max << green_shift;
vs->client_pf.bmax = blue_max ? blue_max : 0xFF;
vs->client_pf.bbits = ctpopl(blue_max);
vs->client_pf.bshift = blue_shift;
- vs->client_pf.bmask = blue_max << blue_shift;
+ vs->client_pf.bmask = (uint32_t)blue_max << blue_shift;
vs->client_pf.bits_per_pixel = bits_per_pixel;
vs->client_pf.bytes_per_pixel = bits_per_pixel / 8;
vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
--
2.55.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 4/5] ui/vnc: use RFB wire types for client message handlers
2026-07-06 12:53 [PATCH 0/5] Various UI/security-related fixes Marc-André Lureau
` (2 preceding siblings ...)
2026-07-06 12:53 ` [PATCH 3/5] ui/vnc: validate color shifts in SetPixelFormat Marc-André Lureau
@ 2026-07-06 12:53 ` Marc-André Lureau
2026-07-13 11:28 ` Philippe Mathieu-Daudé
2026-07-06 12:53 ` [PATCH 5/5] ui/input-barrier: fix off-by-one in keycode bounds check Marc-André Lureau
4 siblings, 1 reply; 13+ messages in thread
From: Marc-André Lureau @ 2026-07-06 12:53 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Marcelo Tosatti, kvm, Daniel P. Berrangé,
Marc-André Lureau
Use exact-width unsigned types for the static functions that process
RFB client messages, matching the types returned by read_u8(),
read_u16(), and read_u32():
- set_pixel_format: uint8_t/uint16_t for pixel format fields
- pointer_event: uint8_t button_mask, uint16_t x/y
- key_event/ext_key_event: bool down, uint32_t sym/keycode
- do_key_event: uint32_t sym
- framebuffer_update_request: uint8_t incremental, uint16_t x/y/w/h
Drop needless declarations.
Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
---
ui/vnc.c | 33 ++++++++++++++-------------------
1 file changed, 14 insertions(+), 19 deletions(-)
diff --git a/ui/vnc.c b/ui/vnc.c
index 94a38242c56..14ce2816907 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -608,15 +608,7 @@ bool vnc_display_reload_certs(const char *id, Error **errp)
3) resolutions > 1024
*/
-static int vnc_update_client(VncState *vs, int has_dirty);
-static void vnc_disconnect_start(VncState *vs);
-
static void vnc_colordepth(VncState *vs);
-static void framebuffer_update_request(VncState *vs, int incremental,
- int x_position, int y_position,
- int w, int h);
-static void vnc_refresh(DisplayChangeListener *dcl);
-static int vnc_refresh_server_surface(VncDisplay *vd);
static int vnc_width(VncDisplay *vd)
{
@@ -1763,7 +1755,8 @@ static void check_pointer_type_change(Notifier *notifier, void *data)
vs->absolute = absolute;
}
-static void pointer_event(VncState *vs, int button_mask, int x, int y)
+static void pointer_event(VncState *vs, uint8_t button_mask,
+ uint16_t x, uint16_t y)
{
static uint32_t bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = 0x01,
@@ -1841,7 +1834,7 @@ static void kbd_leds(Notifier *notifier, void *data)
}
}
-static void do_key_event(VncState *vs, int down, int keycode, int sym)
+static void do_key_event(VncState *vs, int down, int keycode, uint32_t sym)
{
unsigned int lnx = qemu_input_key_number_to_linux(keycode);
@@ -2019,7 +2012,7 @@ static const char *code2name(int keycode)
return QKeyCode_str(qemu_input_key_number_to_qcode(keycode));
}
-static void key_event(VncState *vs, int down, uint32_t sym)
+static void key_event(VncState *vs, bool down, uint32_t sym)
{
int keycode;
int lsym = sym;
@@ -2034,8 +2027,8 @@ static void key_event(VncState *vs, int down, uint32_t sym)
do_key_event(vs, down, keycode, sym);
}
-static void ext_key_event(VncState *vs, int down,
- uint32_t sym, uint16_t keycode)
+static void ext_key_event(VncState *vs, bool down,
+ uint32_t sym, uint32_t keycode)
{
/* if the user specifies a keyboard layout, always use it */
if (keyboard_layout) {
@@ -2046,8 +2039,9 @@ static void ext_key_event(VncState *vs, int down,
}
}
-static void framebuffer_update_request(VncState *vs, int incremental,
- int x, int y, int w, int h)
+static void framebuffer_update_request(VncState *vs, uint8_t incremental,
+ uint16_t x, uint16_t y,
+ uint16_t w, uint16_t h)
{
if (incremental) {
if (vs->update != VNC_STATE_UPDATE_FORCE) {
@@ -2250,10 +2244,11 @@ static void send_color_map(VncState *vs)
vnc_unlock_output(vs);
}
-static void set_pixel_format(VncState *vs, int bits_per_pixel,
- int big_endian_flag, int true_color_flag,
- int red_max, int green_max, int blue_max,
- int red_shift, int green_shift, int blue_shift)
+static void set_pixel_format(VncState *vs, uint8_t bits_per_pixel,
+ uint8_t big_endian_flag, uint8_t true_color_flag,
+ uint16_t red_max, uint16_t green_max,
+ uint16_t blue_max, uint8_t red_shift,
+ uint8_t green_shift, uint8_t blue_shift)
{
if (!true_color_flag) {
/* Expose a reasonable default 256 color map */
--
2.55.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 5/5] ui/input-barrier: fix off-by-one in keycode bounds check
2026-07-06 12:53 [PATCH 0/5] Various UI/security-related fixes Marc-André Lureau
` (3 preceding siblings ...)
2026-07-06 12:53 ` [PATCH 4/5] ui/vnc: use RFB wire types for client message handlers Marc-André Lureau
@ 2026-07-06 12:53 ` Marc-André Lureau
2026-07-10 13:43 ` Laurent Vivier
2026-07-13 11:16 ` Philippe Mathieu-Daudé
4 siblings, 2 replies; 13+ messages in thread
From: Marc-André Lureau @ 2026-07-06 12:53 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Marcelo Tosatti, kvm, Daniel P. Berrangé,
Marc-André Lureau
Use strict "<" to fix the off-by-one.
Fixes: 6105683da35b ("ui: add an embedded Barrier client")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3951
Reported-by: huntr bubble
Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
---
ui/input-barrier.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ui/input-barrier.c b/ui/input-barrier.c
index d07027114af..0a238d4010b 100644
--- a/ui/input-barrier.c
+++ b/ui/input-barrier.c
@@ -87,7 +87,7 @@ static kbd_layout_t *kbd_layout;
static unsigned int input_barrier_to_linux(uint16_t keyid, uint16_t keycode)
{
/* keycode is optional, if it is not provided use keyid */
- if (keycode && keycode <= qemu_input_map_xorgkbd_to_linux_len) {
+ if (keycode && keycode < qemu_input_map_xorgkbd_to_linux_len) {
return qemu_input_map_xorgkbd_to_linux[keycode];
}
--
2.55.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 5/5] ui/input-barrier: fix off-by-one in keycode bounds check
2026-07-06 12:53 ` [PATCH 5/5] ui/input-barrier: fix off-by-one in keycode bounds check Marc-André Lureau
@ 2026-07-10 13:43 ` Laurent Vivier
2026-07-13 11:16 ` Philippe Mathieu-Daudé
1 sibling, 0 replies; 13+ messages in thread
From: Laurent Vivier @ 2026-07-10 13:43 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
Cc: Paolo Bonzini, Marcelo Tosatti, kvm, Daniel P. Berrangé
On 7/6/26 14:53, Marc-André Lureau wrote:
> Use strict "<" to fix the off-by-one.
>
> Fixes: 6105683da35b ("ui: add an embedded Barrier client")
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3951
> Reported-by: huntr bubble
> Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
> ---
> ui/input-barrier.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/ui/input-barrier.c b/ui/input-barrier.c
> index d07027114af..0a238d4010b 100644
> --- a/ui/input-barrier.c
> +++ b/ui/input-barrier.c
> @@ -87,7 +87,7 @@ static kbd_layout_t *kbd_layout;
> static unsigned int input_barrier_to_linux(uint16_t keyid, uint16_t keycode)
> {
> /* keycode is optional, if it is not provided use keyid */
> - if (keycode && keycode <= qemu_input_map_xorgkbd_to_linux_len) {
> + if (keycode && keycode < qemu_input_map_xorgkbd_to_linux_len) {
> return qemu_input_map_xorgkbd_to_linux[keycode];
> }
>
>
Reviewed-by: Laurent Vivier <lvivier@redhat.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/5] i386/tdx: fix uninitialized variable warning in tdx_check_features
2026-07-06 12:53 ` [PATCH 1/5] i386/tdx: fix uninitialized variable warning in tdx_check_features Marc-André Lureau
@ 2026-07-13 11:12 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 13+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-07-13 11:12 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
Cc: Paolo Bonzini, Marcelo Tosatti, kvm, Daniel P. Berrangé
On 6/7/26 14:53, Marc-André Lureau wrote:
> tdx_fetch_cpuid() only sets the output ret parameter on the error
> path. GCC cannot prove that r is always initialized before use in
> the caller, triggering -Werror=maybe-uninitialized.
>
> Initialize r to -1 to silence the warning.
>
> Fixes: 228e40f33048 ("i386/tdx: Fetch and validate CPUID of TD guest")
> Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
> ---
> target/i386/kvm/tdx.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c
> index c9c3b05d5fe..8294dbde3aa 100644
> --- a/target/i386/kvm/tdx.c
> +++ b/target/i386/kvm/tdx.c
> @@ -887,7 +887,7 @@ static int tdx_check_features(X86ConfidentialGuest *cg, CPUState *cs)
> FeatureWordInfo *wi;
> FeatureWord w;
> bool mismatch = false;
> - int r;
> + int r = -1;
>
> fetch_cpuid = tdx_fetch_cpuid(cs, &r);
> if (!fetch_cpuid) {
Alternatively, 'return -1;' here.
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 5/5] ui/input-barrier: fix off-by-one in keycode bounds check
2026-07-06 12:53 ` [PATCH 5/5] ui/input-barrier: fix off-by-one in keycode bounds check Marc-André Lureau
2026-07-10 13:43 ` Laurent Vivier
@ 2026-07-13 11:16 ` Philippe Mathieu-Daudé
1 sibling, 0 replies; 13+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-07-13 11:16 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
Cc: Paolo Bonzini, Marcelo Tosatti, kvm, Daniel P. Berrangé
On 6/7/26 14:53, Marc-André Lureau wrote:
> Use strict "<" to fix the off-by-one.
>
> Fixes: 6105683da35b ("ui: add an embedded Barrier client")
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3951
> Reported-by: huntr bubble
> Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
> ---
> ui/input-barrier.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/5] ui/vnc: validate color shifts in SetPixelFormat
2026-07-06 12:53 ` [PATCH 3/5] ui/vnc: validate color shifts in SetPixelFormat Marc-André Lureau
@ 2026-07-13 11:23 ` Philippe Mathieu-Daudé
2026-07-13 11:27 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 13+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-07-13 11:23 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
Cc: Paolo Bonzini, Marcelo Tosatti, kvm, Daniel P. Berrangé
On 6/7/26 14:53, Marc-André Lureau wrote:
> A malicious VNC client can send a SetPixelFormat message with shift
> values >= 32, causing UB mask computation
> (e.g. red_max << red_shift where red_shift is 255). Apparently, this is
> not covered by -fwrapv.
>
> Reject color shifts >= bits_per_pixel before computing masks, and cast
> the max values to uint32_t to avoid signed integer overflow when a
> valid shift (e.g. 24) would set bit 31 of a signed int.
>
> Fixes: 9f64916da20 ("pixman/vnc: use pixman images in vnc.")
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3948
> Reported-by: huntr bubble
> Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
> ---
> ui/vnc.c | 13 ++++++++++---
> 1 file changed, 10 insertions(+), 3 deletions(-)
>
> diff --git a/ui/vnc.c b/ui/vnc.c
> index 559d3954b87..94a38242c56 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -2276,18 +2276,25 @@ static void set_pixel_format(VncState *vs, int bits_per_pixel,
> return;
> }
>
> + if (red_shift >= bits_per_pixel ||
> + green_shift >= bits_per_pixel ||
> + blue_shift >= bits_per_pixel) {
> + vnc_client_error(vs);
> + return;
> + }
> +
> vs->client_pf.rmax = red_max ? red_max : 0xFF;
> vs->client_pf.rbits = ctpopl(red_max);
> vs->client_pf.rshift = red_shift;
> - vs->client_pf.rmask = red_max << red_shift;
> + vs->client_pf.rmask = (uint32_t)red_max << red_shift;
> vs->client_pf.gmax = green_max ? green_max : 0xFF;
> vs->client_pf.gbits = ctpopl(green_max);
> vs->client_pf.gshift = green_shift;
> - vs->client_pf.gmask = green_max << green_shift;
> + vs->client_pf.gmask = (uint32_t)green_max << green_shift;
> vs->client_pf.bmax = blue_max ? blue_max : 0xFF;
> vs->client_pf.bbits = ctpopl(blue_max);
> vs->client_pf.bshift = blue_shift;
> - vs->client_pf.bmask = blue_max << blue_shift;
> + vs->client_pf.bmask = (uint32_t)blue_max << blue_shift;
> vs->client_pf.bits_per_pixel = bits_per_pixel;
> vs->client_pf.bytes_per_pixel = bits_per_pixel / 8;
> vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
>
What about instead of the casts (keeping the if(shift) block):
-static void set_pixel_format(VncState *vs, int bits_per_pixel,
- int big_endian_flag, int true_color_flag,
- int red_max, int green_max, int blue_max,
- int red_shift, int green_shift, int
blue_shift)
+static void set_pixel_format(VncState *vs, uint8_t bits_per_pixel,
+ bool big_endian_flag, bool true_color_flag,
+ uint16_t red_max, uint16_t green_max,
uint16_t blue_max,
+ uint8_t red_shift, uint8_t green_shift,
uint8_t blue_shift)
?
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/5] ui/vnc: fix OOB write in vnc_refresh_lossy_rect
2026-07-06 12:53 ` [PATCH 2/5] ui/vnc: fix OOB write in vnc_refresh_lossy_rect Marc-André Lureau
@ 2026-07-13 11:24 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 13+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-07-13 11:24 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
Cc: Paolo Bonzini, Marcelo Tosatti, kvm, Daniel P. Berrangé
On 6/7/26 14:53, Marc-André Lureau wrote:
> vnc_refresh_lossy_rect() always marks a full VNC_STAT_RECT (64) rows
> as dirty when refreshing a lossy tile. When the display height is not
> a multiple of VNC_STAT_RECT (e.g. VNC_MAX_HEIGHT = 2160), the bottom
> tile is partial -- the last tile at y=2112 has only 48 valid rows.
> The unclamped loop writes to vs->dirty[2160..2175], past the end of
> the VNC_MAX_HEIGHT-sized array.
>
> Clamp the row count to the actual surface height so partial bottom
> tiles only mark valid dirty bitmap entries.
>
> Fixes: CVE-2026-48002
> Fixes: 7d964c9d2fc6 ("vnc: refresh lossy rect after a given timeout")
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3950
> Reported-by: huntr bubble
> Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
> ---
> ui/vnc.c | 10 +++++++++-
> 1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/ui/vnc.c b/ui/vnc.c
> index b2b69923b75..559d3954b87 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -3004,10 +3004,18 @@ static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
> int sty = y / VNC_STAT_RECT;
> int stx = x / VNC_STAT_RECT;
> int has_dirty = 0;
> + int height = MIN(pixman_image_get_height(vd->guest.fb),
> + pixman_image_get_height(vd->server));
This could deserve some helper, anyway:
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> + int rows;
>
> y = QEMU_ALIGN_DOWN(y, VNC_STAT_RECT);
> x = QEMU_ALIGN_DOWN(x, VNC_STAT_RECT);
>
> + rows = MIN(VNC_STAT_RECT, height - y);
> + if (rows <= 0) {
> + return 0;
> + }
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/5] ui/vnc: validate color shifts in SetPixelFormat
2026-07-13 11:23 ` Philippe Mathieu-Daudé
@ 2026-07-13 11:27 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 13+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-07-13 11:27 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
Cc: Paolo Bonzini, Marcelo Tosatti, kvm, Daniel P. Berrangé
On 13/7/26 13:23, Philippe Mathieu-Daudé wrote:
> On 6/7/26 14:53, Marc-André Lureau wrote:
>> A malicious VNC client can send a SetPixelFormat message with shift
>> values >= 32, causing UB mask computation
>> (e.g. red_max << red_shift where red_shift is 255). Apparently, this is
>> not covered by -fwrapv.
>>
>> Reject color shifts >= bits_per_pixel before computing masks, and cast
>> the max values to uint32_t to avoid signed integer overflow when a
>> valid shift (e.g. 24) would set bit 31 of a signed int.
>>
>> Fixes: 9f64916da20 ("pixman/vnc: use pixman images in vnc.")
>> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3948
>> Reported-by: huntr bubble
>> Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
>> ---
>> ui/vnc.c | 13 ++++++++++---
>> 1 file changed, 10 insertions(+), 3 deletions(-)
>>
>> diff --git a/ui/vnc.c b/ui/vnc.c
>> index 559d3954b87..94a38242c56 100644
>> --- a/ui/vnc.c
>> +++ b/ui/vnc.c
>> @@ -2276,18 +2276,25 @@ static void set_pixel_format(VncState *vs, int
>> bits_per_pixel,
>> return;
>> }
>> + if (red_shift >= bits_per_pixel ||
>> + green_shift >= bits_per_pixel ||
>> + blue_shift >= bits_per_pixel) {
>> + vnc_client_error(vs);
>> + return;
>> + }
>> +
>> vs->client_pf.rmax = red_max ? red_max : 0xFF;
>> vs->client_pf.rbits = ctpopl(red_max);
>> vs->client_pf.rshift = red_shift;
>> - vs->client_pf.rmask = red_max << red_shift;
>> + vs->client_pf.rmask = (uint32_t)red_max << red_shift;
>> vs->client_pf.gmax = green_max ? green_max : 0xFF;
>> vs->client_pf.gbits = ctpopl(green_max);
>> vs->client_pf.gshift = green_shift;
>> - vs->client_pf.gmask = green_max << green_shift;
>> + vs->client_pf.gmask = (uint32_t)green_max << green_shift;
>> vs->client_pf.bmax = blue_max ? blue_max : 0xFF;
>> vs->client_pf.bbits = ctpopl(blue_max);
>> vs->client_pf.bshift = blue_shift;
>> - vs->client_pf.bmask = blue_max << blue_shift;
>> + vs->client_pf.bmask = (uint32_t)blue_max << blue_shift;
>> vs->client_pf.bits_per_pixel = bits_per_pixel;
>> vs->client_pf.bytes_per_pixel = bits_per_pixel / 8;
>> vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
>>
>
> What about instead of the casts (keeping the if(shift) block):
>
> -static void set_pixel_format(VncState *vs, int bits_per_pixel,
> - int big_endian_flag, int true_color_flag,
> - int red_max, int green_max, int blue_max,
> - int red_shift, int green_shift, int
> blue_shift)
> +static void set_pixel_format(VncState *vs, uint8_t bits_per_pixel,
> + bool big_endian_flag, bool true_color_flag,
> + uint16_t red_max, uint16_t green_max,
> uint16_t blue_max,
> + uint8_t red_shift, uint8_t green_shift,
> uint8_t blue_shift)
>
> ?
Haha this is what the next patch does ;) I got confused by the
(uint32_t) casts, they belong to the next patch.
So with only the if(shift) here:
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 4/5] ui/vnc: use RFB wire types for client message handlers
2026-07-06 12:53 ` [PATCH 4/5] ui/vnc: use RFB wire types for client message handlers Marc-André Lureau
@ 2026-07-13 11:28 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 13+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-07-13 11:28 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
Cc: Paolo Bonzini, Marcelo Tosatti, kvm, Daniel P. Berrangé
On 6/7/26 14:53, Marc-André Lureau wrote:
> Use exact-width unsigned types for the static functions that process
> RFB client messages, matching the types returned by read_u8(),
> read_u16(), and read_u32():
>
> - set_pixel_format: uint8_t/uint16_t for pixel format fields
> - pointer_event: uint8_t button_mask, uint16_t x/y
> - key_event/ext_key_event: bool down, uint32_t sym/keycode
> - do_key_event: uint32_t sym
> - framebuffer_update_request: uint8_t incremental, uint16_t x/y/w/h
>
> Drop needless declarations.
>
> Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
> ---
> ui/vnc.c | 33 ++++++++++++++-------------------
> 1 file changed, 14 insertions(+), 19 deletions(-)
>
> diff --git a/ui/vnc.c b/ui/vnc.c
> index 94a38242c56..14ce2816907 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -608,15 +608,7 @@ bool vnc_display_reload_certs(const char *id, Error **errp)
> 3) resolutions > 1024
> */
>
> -static int vnc_update_client(VncState *vs, int has_dirty);
> -static void vnc_disconnect_start(VncState *vs);
> -
> static void vnc_colordepth(VncState *vs);
> -static void framebuffer_update_request(VncState *vs, int incremental,
> - int x_position, int y_position,
> - int w, int h);
> -static void vnc_refresh(DisplayChangeListener *dcl);
> -static int vnc_refresh_server_surface(VncDisplay *vd);
>
> static int vnc_width(VncDisplay *vd)
> {
> @@ -1763,7 +1755,8 @@ static void check_pointer_type_change(Notifier *notifier, void *data)
> vs->absolute = absolute;
> }
>
> -static void pointer_event(VncState *vs, int button_mask, int x, int y)
> +static void pointer_event(VncState *vs, uint8_t button_mask,
> + uint16_t x, uint16_t y)
> {
> static uint32_t bmap[INPUT_BUTTON__MAX] = {
> [INPUT_BUTTON_LEFT] = 0x01,
> @@ -1841,7 +1834,7 @@ static void kbd_leds(Notifier *notifier, void *data)
> }
> }
>
> -static void do_key_event(VncState *vs, int down, int keycode, int sym)
> +static void do_key_event(VncState *vs, int down, int keycode, uint32_t sym)
bool down.
> {
> unsigned int lnx = qemu_input_key_number_to_linux(keycode);
>
> @@ -2019,7 +2012,7 @@ static const char *code2name(int keycode)
> return QKeyCode_str(qemu_input_key_number_to_qcode(keycode));
> }
>
> -static void key_event(VncState *vs, int down, uint32_t sym)
> +static void key_event(VncState *vs, bool down, uint32_t sym)
> {
> int keycode;
> int lsym = sym;
> @@ -2034,8 +2027,8 @@ static void key_event(VncState *vs, int down, uint32_t sym)
> do_key_event(vs, down, keycode, sym);
> }
>
> -static void ext_key_event(VncState *vs, int down,
> - uint32_t sym, uint16_t keycode)
> +static void ext_key_event(VncState *vs, bool down,
> + uint32_t sym, uint32_t keycode)
> {
> /* if the user specifies a keyboard layout, always use it */
> if (keyboard_layout) {
> @@ -2046,8 +2039,9 @@ static void ext_key_event(VncState *vs, int down,
> }
> }
>
> -static void framebuffer_update_request(VncState *vs, int incremental,
> - int x, int y, int w, int h)
> +static void framebuffer_update_request(VncState *vs, uint8_t incremental,
> + uint16_t x, uint16_t y,
> + uint16_t w, uint16_t h)
> {
> if (incremental) {
> if (vs->update != VNC_STATE_UPDATE_FORCE) {
> @@ -2250,10 +2244,11 @@ static void send_color_map(VncState *vs)
> vnc_unlock_output(vs);
> }
>
> -static void set_pixel_format(VncState *vs, int bits_per_pixel,
> - int big_endian_flag, int true_color_flag,
> - int red_max, int green_max, int blue_max,
> - int red_shift, int green_shift, int blue_shift)
> +static void set_pixel_format(VncState *vs, uint8_t bits_per_pixel,
> + uint8_t big_endian_flag, uint8_t true_color_flag,
bool flag, bool flag.
> + uint16_t red_max, uint16_t green_max,
> + uint16_t blue_max, uint8_t red_shift,
> + uint8_t green_shift, uint8_t blue_shift)
> {
> if (!true_color_flag) {
> /* Expose a reasonable default 256 color map */
>
Including the (uint32_t) casts in this patch:
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-07-13 11:28 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-06 12:53 [PATCH 0/5] Various UI/security-related fixes Marc-André Lureau
2026-07-06 12:53 ` [PATCH 1/5] i386/tdx: fix uninitialized variable warning in tdx_check_features Marc-André Lureau
2026-07-13 11:12 ` Philippe Mathieu-Daudé
2026-07-06 12:53 ` [PATCH 2/5] ui/vnc: fix OOB write in vnc_refresh_lossy_rect Marc-André Lureau
2026-07-13 11:24 ` Philippe Mathieu-Daudé
2026-07-06 12:53 ` [PATCH 3/5] ui/vnc: validate color shifts in SetPixelFormat Marc-André Lureau
2026-07-13 11:23 ` Philippe Mathieu-Daudé
2026-07-13 11:27 ` Philippe Mathieu-Daudé
2026-07-06 12:53 ` [PATCH 4/5] ui/vnc: use RFB wire types for client message handlers Marc-André Lureau
2026-07-13 11:28 ` Philippe Mathieu-Daudé
2026-07-06 12:53 ` [PATCH 5/5] ui/input-barrier: fix off-by-one in keycode bounds check Marc-André Lureau
2026-07-10 13:43 ` Laurent Vivier
2026-07-13 11:16 ` Philippe Mathieu-Daudé
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.