提交 f9119a25 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/kraxel/tags/pull-vnc-20140701-1' into staging

vnc: two bugfixes (by Peter Lieven).

# gpg: Signature made Tue 01 Jul 2014 12:32:19 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-vnc-20140701-1:
  ui/vnc: fix potential memory corruption issues
  ui/vnc: limit client_cut_text msg payload size
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
...@@ -432,14 +432,10 @@ static void framebuffer_update_request(VncState *vs, int incremental, ...@@ -432,14 +432,10 @@ static void framebuffer_update_request(VncState *vs, int incremental,
static void vnc_refresh(DisplayChangeListener *dcl); static void vnc_refresh(DisplayChangeListener *dcl);
static int vnc_refresh_server_surface(VncDisplay *vd); static int vnc_refresh_server_surface(VncDisplay *vd);
static void vnc_dpy_update(DisplayChangeListener *dcl, static void vnc_set_area_dirty(DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT],
int x, int y, int w, int h) VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT),
{ int width, int height,
VncDisplay *vd = container_of(dcl, VncDisplay, dcl); int x, int y, int w, int h) {
struct VncSurface *s = &vd->guest;
int width = surface_width(vd->ds);
int height = surface_height(vd->ds);
/* this is needed this to ensure we updated all affected /* this is needed this to ensure we updated all affected
* blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */ * blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */
w += (x % VNC_DIRTY_PIXELS_PER_BIT); w += (x % VNC_DIRTY_PIXELS_PER_BIT);
...@@ -451,11 +447,22 @@ static void vnc_dpy_update(DisplayChangeListener *dcl, ...@@ -451,11 +447,22 @@ static void vnc_dpy_update(DisplayChangeListener *dcl,
h = MIN(y + h, height); h = MIN(y + h, height);
for (; y < h; y++) { for (; y < h; y++) {
bitmap_set(s->dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT, bitmap_set(dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT,
DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT)); DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));
} }
} }
static void vnc_dpy_update(DisplayChangeListener *dcl,
int x, int y, int w, int h)
{
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
struct VncSurface *s = &vd->guest;
int width = pixman_image_get_width(vd->server);
int height = pixman_image_get_height(vd->server);
vnc_set_area_dirty(s->dirty, width, height, x, y, w, h);
}
void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
int32_t encoding) int32_t encoding)
{ {
...@@ -517,17 +524,15 @@ void buffer_advance(Buffer *buf, size_t len) ...@@ -517,17 +524,15 @@ void buffer_advance(Buffer *buf, size_t len)
static void vnc_desktop_resize(VncState *vs) static void vnc_desktop_resize(VncState *vs)
{ {
DisplaySurface *ds = vs->vd->ds;
if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) { if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
return; return;
} }
if (vs->client_width == surface_width(ds) && if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
vs->client_height == surface_height(ds)) { vs->client_height == pixman_image_get_height(vs->vd->server)) {
return; return;
} }
vs->client_width = surface_width(ds); vs->client_width = pixman_image_get_width(vs->vd->server);
vs->client_height = surface_height(ds); vs->client_height = pixman_image_get_height(vs->vd->server);
vnc_lock_output(vs); vnc_lock_output(vs);
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
vnc_write_u8(vs, 0); vnc_write_u8(vs, 0);
...@@ -571,31 +576,24 @@ void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y) ...@@ -571,31 +576,24 @@ void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y)
ptr += x * VNC_SERVER_FB_BYTES; ptr += x * VNC_SERVER_FB_BYTES;
return ptr; return ptr;
} }
/* this sets only the visible pixels of a dirty bitmap */
#define VNC_SET_VISIBLE_PIXELS_DIRTY(bitmap, w, h) {\
int y;\
memset(bitmap, 0x00, sizeof(bitmap));\
for (y = 0; y < h; y++) {\
bitmap_set(bitmap[y], 0,\
DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));\
} \
}
static void vnc_dpy_switch(DisplayChangeListener *dcl, static void vnc_dpy_switch(DisplayChangeListener *dcl,
DisplaySurface *surface) DisplaySurface *surface)
{ {
VncDisplay *vd = container_of(dcl, VncDisplay, dcl); VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
VncState *vs; VncState *vs;
int width, height;
vnc_abort_display_jobs(vd); vnc_abort_display_jobs(vd);
/* server surface */ /* server surface */
qemu_pixman_image_unref(vd->server); qemu_pixman_image_unref(vd->server);
vd->ds = surface; vd->ds = surface;
width = MIN(VNC_MAX_WIDTH, ROUND_UP(surface_width(vd->ds),
VNC_DIRTY_PIXELS_PER_BIT));
height = MIN(VNC_MAX_HEIGHT, surface_height(vd->ds));
vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT, vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
surface_width(vd->ds), width, height, NULL, 0);
surface_height(vd->ds),
NULL, 0);
/* guest surface */ /* guest surface */
#if 0 /* FIXME */ #if 0 /* FIXME */
...@@ -605,9 +603,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, ...@@ -605,9 +603,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
qemu_pixman_image_unref(vd->guest.fb); qemu_pixman_image_unref(vd->guest.fb);
vd->guest.fb = pixman_image_ref(surface->image); vd->guest.fb = pixman_image_ref(surface->image);
vd->guest.format = surface->format; vd->guest.format = surface->format;
VNC_SET_VISIBLE_PIXELS_DIRTY(vd->guest.dirty, memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty));
surface_width(vd->ds), vnc_set_area_dirty(vd->guest.dirty, width, height, 0, 0,
surface_height(vd->ds)); width, height);
QTAILQ_FOREACH(vs, &vd->clients, next) { QTAILQ_FOREACH(vs, &vd->clients, next) {
vnc_colordepth(vs); vnc_colordepth(vs);
...@@ -615,9 +613,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, ...@@ -615,9 +613,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
if (vs->vd->cursor) { if (vs->vd->cursor) {
vnc_cursor_define(vs); vnc_cursor_define(vs);
} }
VNC_SET_VISIBLE_PIXELS_DIRTY(vs->dirty, memset(vs->dirty, 0x00, sizeof(vs->dirty));
surface_width(vd->ds), vnc_set_area_dirty(vs->dirty, width, height, 0, 0,
surface_height(vd->ds)); width, height);
} }
} }
...@@ -911,8 +909,8 @@ static int vnc_update_client(VncState *vs, int has_dirty, bool sync) ...@@ -911,8 +909,8 @@ static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
*/ */
job = vnc_job_new(vs); job = vnc_job_new(vs);
height = MIN(pixman_image_get_height(vd->server), vs->client_height); height = pixman_image_get_height(vd->server);
width = MIN(pixman_image_get_width(vd->server), vs->client_width); width = pixman_image_get_width(vd->server);
y = 0; y = 0;
for (;;) { for (;;) {
...@@ -1501,8 +1499,8 @@ static void check_pointer_type_change(Notifier *notifier, void *data) ...@@ -1501,8 +1499,8 @@ static void check_pointer_type_change(Notifier *notifier, void *data)
vnc_write_u8(vs, 0); vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1); vnc_write_u16(vs, 1);
vnc_framebuffer_update(vs, absolute, 0, vnc_framebuffer_update(vs, absolute, 0,
surface_width(vs->vd->ds), pixman_image_get_width(vs->vd->server),
surface_height(vs->vd->ds), pixman_image_get_height(vs->vd->server),
VNC_ENCODING_POINTER_TYPE_CHANGE); VNC_ENCODING_POINTER_TYPE_CHANGE);
vnc_unlock_output(vs); vnc_unlock_output(vs);
vnc_flush(vs); vnc_flush(vs);
...@@ -1520,8 +1518,8 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y) ...@@ -1520,8 +1518,8 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y)
[INPUT_BUTTON_WHEEL_DOWN] = 0x10, [INPUT_BUTTON_WHEEL_DOWN] = 0x10,
}; };
QemuConsole *con = vs->vd->dcl.con; QemuConsole *con = vs->vd->dcl.con;
int width = surface_width(vs->vd->ds); int width = pixman_image_get_width(vs->vd->server);
int height = surface_height(vs->vd->ds); int height = pixman_image_get_height(vs->vd->server);
if (vs->last_bmask != button_mask) { if (vs->last_bmask != button_mask) {
qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask); qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask);
...@@ -1869,29 +1867,18 @@ static void ext_key_event(VncState *vs, int down, ...@@ -1869,29 +1867,18 @@ static void ext_key_event(VncState *vs, int down,
} }
static void framebuffer_update_request(VncState *vs, int incremental, static void framebuffer_update_request(VncState *vs, int incremental,
int x_position, int y_position, int x, int y, int w, int h)
int w, int h)
{ {
int i; int width = pixman_image_get_width(vs->vd->server);
const size_t width = surface_width(vs->vd->ds) / VNC_DIRTY_PIXELS_PER_BIT; int height = pixman_image_get_height(vs->vd->server);
const size_t height = surface_height(vs->vd->ds);
if (y_position > height) {
y_position = height;
}
if (y_position + h >= height) {
h = height - y_position;
}
vs->need_update = 1; vs->need_update = 1;
if (!incremental) {
vs->force_update = 1; if (incremental) {
for (i = 0; i < h; i++) { return;
bitmap_set(vs->dirty[y_position + i], 0, width);
bitmap_clear(vs->dirty[y_position + i], width,
VNC_DIRTY_BITS - width);
}
} }
vnc_set_area_dirty(vs->dirty, width, height, x, y, w, h);
} }
static void send_ext_key_event_ack(VncState *vs) static void send_ext_key_event_ack(VncState *vs)
...@@ -1901,8 +1888,8 @@ static void send_ext_key_event_ack(VncState *vs) ...@@ -1901,8 +1888,8 @@ static void send_ext_key_event_ack(VncState *vs)
vnc_write_u8(vs, 0); vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1); vnc_write_u16(vs, 1);
vnc_framebuffer_update(vs, 0, 0, vnc_framebuffer_update(vs, 0, 0,
surface_width(vs->vd->ds), pixman_image_get_width(vs->vd->server),
surface_height(vs->vd->ds), pixman_image_get_height(vs->vd->server),
VNC_ENCODING_EXT_KEY_EVENT); VNC_ENCODING_EXT_KEY_EVENT);
vnc_unlock_output(vs); vnc_unlock_output(vs);
vnc_flush(vs); vnc_flush(vs);
...@@ -1915,8 +1902,8 @@ static void send_ext_audio_ack(VncState *vs) ...@@ -1915,8 +1902,8 @@ static void send_ext_audio_ack(VncState *vs)
vnc_write_u8(vs, 0); vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1); vnc_write_u16(vs, 1);
vnc_framebuffer_update(vs, 0, 0, vnc_framebuffer_update(vs, 0, 0,
surface_width(vs->vd->ds), pixman_image_get_width(vs->vd->server),
surface_height(vs->vd->ds), pixman_image_get_height(vs->vd->server),
VNC_ENCODING_AUDIO); VNC_ENCODING_AUDIO);
vnc_unlock_output(vs); vnc_unlock_output(vs);
vnc_flush(vs); vnc_flush(vs);
...@@ -2094,8 +2081,8 @@ static void vnc_colordepth(VncState *vs) ...@@ -2094,8 +2081,8 @@ static void vnc_colordepth(VncState *vs)
vnc_write_u8(vs, 0); vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1); /* number of rects */ vnc_write_u16(vs, 1); /* number of rects */
vnc_framebuffer_update(vs, 0, 0, vnc_framebuffer_update(vs, 0, 0,
surface_width(vs->vd->ds), pixman_image_get_width(vs->vd->server),
surface_height(vs->vd->ds), pixman_image_get_height(vs->vd->server),
VNC_ENCODING_WMVi); VNC_ENCODING_WMVi);
pixel_format_message(vs); pixel_format_message(vs);
vnc_unlock_output(vs); vnc_unlock_output(vs);
...@@ -2165,13 +2152,20 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) ...@@ -2165,13 +2152,20 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4)); pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
break; break;
case VNC_MSG_CLIENT_CUT_TEXT: case VNC_MSG_CLIENT_CUT_TEXT:
if (len == 1) if (len == 1) {
return 8; return 8;
}
if (len == 8) { if (len == 8) {
uint32_t dlen = read_u32(data, 4); uint32_t dlen = read_u32(data, 4);
if (dlen > 0) if (dlen > (1 << 20)) {
error_report("vnc: client_cut_text msg payload has %u bytes"
" which exceeds our limit of 1MB.", dlen);
vnc_client_error(vs);
break;
}
if (dlen > 0) {
return 8 + dlen; return 8 + dlen;
}
} }
client_cut_text(vs, read_u32(data, 4), data + 8); client_cut_text(vs, read_u32(data, 4), data + 8);
...@@ -2310,8 +2304,8 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len) ...@@ -2310,8 +2304,8 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
} }
vnc_set_share_mode(vs, mode); vnc_set_share_mode(vs, mode);
vs->client_width = surface_width(vs->vd->ds); vs->client_width = pixman_image_get_width(vs->vd->server);
vs->client_height = surface_height(vs->vd->ds); vs->client_height = pixman_image_get_height(vs->vd->server);
vnc_write_u16(vs, vs->client_width); vnc_write_u16(vs, vs->client_width);
vnc_write_u16(vs, vs->client_height); vnc_write_u16(vs, vs->client_height);
...@@ -2678,12 +2672,12 @@ static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv) ...@@ -2678,12 +2672,12 @@ static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
static int vnc_refresh_server_surface(VncDisplay *vd) static int vnc_refresh_server_surface(VncDisplay *vd)
{ {
int width = pixman_image_get_width(vd->guest.fb); int width = MIN(pixman_image_get_width(vd->guest.fb),
int height = pixman_image_get_height(vd->guest.fb); pixman_image_get_width(vd->server));
int y; int height = MIN(pixman_image_get_height(vd->guest.fb),
pixman_image_get_height(vd->server));
int cmp_bytes, server_stride, min_stride, guest_stride, y = 0;
uint8_t *guest_row0 = NULL, *server_row0; uint8_t *guest_row0 = NULL, *server_row0;
int guest_stride = 0, server_stride;
int cmp_bytes;
VncState *vs; VncState *vs;
int has_dirty = 0; int has_dirty = 0;
pixman_image_t *tmpbuf = NULL; pixman_image_t *tmpbuf = NULL;
...@@ -2700,10 +2694,10 @@ static int vnc_refresh_server_surface(VncDisplay *vd) ...@@ -2700,10 +2694,10 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
* Check and copy modified bits from guest to server surface. * Check and copy modified bits from guest to server surface.
* Update server dirty map. * Update server dirty map.
*/ */
cmp_bytes = VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES; server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
if (cmp_bytes > vnc_server_fb_stride(vd)) { server_stride = guest_stride = pixman_image_get_stride(vd->server);
cmp_bytes = vnc_server_fb_stride(vd); cmp_bytes = MIN(VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES,
} server_stride);
if (vd->guest.format != VNC_SERVER_FB_FORMAT) { if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
int width = pixman_image_get_width(vd->server); int width = pixman_image_get_width(vd->server);
tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width); tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width);
...@@ -2711,10 +2705,8 @@ static int vnc_refresh_server_surface(VncDisplay *vd) ...@@ -2711,10 +2705,8 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb); guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb);
guest_stride = pixman_image_get_stride(vd->guest.fb); guest_stride = pixman_image_get_stride(vd->guest.fb);
} }
server_row0 = (uint8_t *)pixman_image_get_data(vd->server); min_stride = MIN(server_stride, guest_stride);
server_stride = pixman_image_get_stride(vd->server);
y = 0;
for (;;) { for (;;) {
int x; int x;
uint8_t *guest_ptr, *server_ptr; uint8_t *guest_ptr, *server_ptr;
...@@ -2740,13 +2732,17 @@ static int vnc_refresh_server_surface(VncDisplay *vd) ...@@ -2740,13 +2732,17 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
for (; x < DIV_ROUND_UP(width, VNC_DIRTY_PIXELS_PER_BIT); for (; x < DIV_ROUND_UP(width, VNC_DIRTY_PIXELS_PER_BIT);
x++, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) { x++, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
int _cmp_bytes = cmp_bytes;
if (!test_and_clear_bit(x, vd->guest.dirty[y])) { if (!test_and_clear_bit(x, vd->guest.dirty[y])) {
continue; continue;
} }
if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0) { if ((x + 1) * cmp_bytes > min_stride) {
_cmp_bytes = min_stride - x * cmp_bytes;
}
if (memcmp(server_ptr, guest_ptr, _cmp_bytes) == 0) {
continue; continue;
} }
memcpy(server_ptr, guest_ptr, cmp_bytes); memcpy(server_ptr, guest_ptr, _cmp_bytes);
if (!vd->non_adaptive) { if (!vd->non_adaptive) {
vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT, vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT,
y, &tv); y, &tv);
......
...@@ -77,14 +77,15 @@ typedef void VncSendHextileTile(VncState *vs, ...@@ -77,14 +77,15 @@ typedef void VncSendHextileTile(VncState *vs,
void *last_fg, void *last_fg,
int *has_bg, int *has_fg); int *has_bg, int *has_fg);
/* VNC_MAX_WIDTH must be a multiple of 16. */
#define VNC_MAX_WIDTH 2560
#define VNC_MAX_HEIGHT 2048
/* VNC_DIRTY_PIXELS_PER_BIT is the number of dirty pixels represented /* VNC_DIRTY_PIXELS_PER_BIT is the number of dirty pixels represented
* by one bit in the dirty bitmap */ * by one bit in the dirty bitmap, should be a power of 2 */
#define VNC_DIRTY_PIXELS_PER_BIT 16 #define VNC_DIRTY_PIXELS_PER_BIT 16
/* VNC_MAX_WIDTH must be a multiple of VNC_DIRTY_PIXELS_PER_BIT. */
#define VNC_MAX_WIDTH ROUND_UP(2560, VNC_DIRTY_PIXELS_PER_BIT)
#define VNC_MAX_HEIGHT 2048
/* VNC_DIRTY_BITS is the number of bits in the dirty bitmap. */ /* VNC_DIRTY_BITS is the number of bits in the dirty bitmap. */
#define VNC_DIRTY_BITS (VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT) #define VNC_DIRTY_BITS (VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT)
...@@ -126,7 +127,8 @@ typedef struct VncRectStat VncRectStat; ...@@ -126,7 +127,8 @@ typedef struct VncRectStat VncRectStat;
struct VncSurface struct VncSurface
{ {
struct timeval last_freq_check; struct timeval last_freq_check;
DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_MAX_WIDTH / 16); DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT],
VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT);
VncRectStat stats[VNC_STAT_ROWS][VNC_STAT_COLS]; VncRectStat stats[VNC_STAT_ROWS][VNC_STAT_COLS];
pixman_image_t *fb; pixman_image_t *fb;
pixman_format_code_t format; pixman_format_code_t format;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册