Index: xen-3.2-testing/tools/ioemu/hw/xenfb.c =================================================================== --- xen-3.2-testing.orig/tools/ioemu/hw/xenfb.c 2008-04-29 08:52:06.000000000 -0600 +++ xen-3.2-testing/tools/ioemu/hw/xenfb.c 2008-04-29 10:12:41.000000000 -0600 @@ -23,8 +23,6 @@ #define BTN_LEFT 0x110 /* from */ #endif -// FIXME defend against malicious frontend? - struct xenfb; struct xenfb_device { @@ -50,6 +48,7 @@ int depth; /* colour depth of guest framebuffer */ int width; /* pixel width of guest framebuffer */ int height; /* pixel height of guest framebuffer */ + int offset; /* offset of the framebuffer */ int abs_pointer_wanted; /* Whether guest supports absolute pointer */ int button_state; /* Last seen pointer button state */ char protocol[64]; /* frontend protocol */ @@ -476,6 +475,75 @@ free(xenfb); } +static int xenfb_configure_fb(struct xenfb *xenfb, size_t fb_len_lim, + int width, int height, int depth, + size_t fb_len, int offset, int row_stride) +{ + size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd); + size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz; + size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz; + size_t fb_len_max = fb_pages * XC_PAGE_SIZE; + int max_width, max_height; + + if (fb_len_lim == 0) { + fprintf(stderr, + "FB: No fb size limit, limit set to %zu\n", + fb_len_max); + fb_len_lim = fb_len_max; + } + if (fb_len_lim > fb_len_max) { + fprintf(stderr, + "FB: fb size limit %zu exceeds %zu, corrected\n", + fb_len_lim, fb_len_max); + fb_len_lim = fb_len_max; + } + if (fb_len > fb_len_lim) { + fprintf(stderr, + "FB: frontend fb size %zu limited to %zu\n", + fb_len, fb_len_lim); + fb_len = fb_len_lim; + } + if (depth != 8 && depth != 16 && depth != 24 && depth != 32) { + fprintf(stderr, + "FB: can't handle frontend fb depth %d\n", + depth); + return -1; + } + if (row_stride < 0 || row_stride > fb_len) { + fprintf(stderr, + "FB: invalid frontend stride %d\n", row_stride); + return -1; + } + max_width = row_stride / (depth / 8); + if (width < 0 || width > max_width) { + fprintf(stderr, + "FB: invalid frontend width %d limited to %d\n", + width, max_width); + width = max_width; + } + if (offset < 0 || offset >= fb_len) { + fprintf(stderr, + "FB: invalid frontend offset %d (max %zu)\n", + offset, fb_len - 1); + return -1; + } + max_height = (fb_len - offset) / row_stride; + if (height < 0 || height > max_height) { + fprintf(stderr, + "FB: invalid frontend height %d limited to %d\n", + height, max_height); + height = max_height; + } + xenfb->fb_len = fb_len; + xenfb->row_stride = row_stride; + xenfb->depth = depth; + xenfb->width = width; + xenfb->height = height; + xenfb->offset = offset; + fprintf(stderr, "Framebuffer %dx%dx%d offset %d stride %d\n", + width, height, depth, offset, row_stride); + return 0; +} static void xenfb_on_fb_event(struct xenfb *xenfb) { @@ -511,10 +579,17 @@ xenfb_guest_copy(xenfb, x, y, w, h); break; case XENFB_TYPE_RESIZE: - xenfb->width = event->resize.width; - xenfb->height = event->resize.height; - xenfb->row_stride = event->resize.stride; + if (xenfb_configure_fb(xenfb, xenfb->fb_len, + event->resize.width, + event->resize.height, + event->resize.depth, + xenfb->fb_len, + 0, + event->resize.stride) < 0) + break; + dpy_resize(xenfb->ds, xenfb->width, xenfb->height); + xenfb_invalidate(xenfb); break; } } @@ -695,22 +770,14 @@ if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.nodename, "videoram", "%d", &videoram) < 0) videoram = 0; - videoram = videoram * 1024 * 1024; fb_page = xenfb->fb.page; - xenfb->depth = fb_page->depth; - xenfb->width = fb_page->width; - xenfb->height = fb_page->height; - xenfb->fb_len = fb_page->mem_length; - xenfb->row_stride = fb_page->line_length; - /* Protect against hostile frontend, limit fb_len to configured */ - if (videoram && xenfb->fb_len > videoram) { - xenfb->fb_len = videoram; - if (xenfb->row_stride * xenfb->height > xenfb->fb_len) - xenfb->height = xenfb->fb_len / xenfb->row_stride; + if (xenfb_configure_fb(xenfb, videoram * 1024 * 1024U, + fb_page->width, fb_page->height, fb_page->depth, + fb_page->mem_length, 0, fb_page->line_length) < 0) { + errno = EINVAL; + return -1; } - fprintf(stderr, "Framebuffer depth %d width %d height %d line %d\n", - fb_page->depth, fb_page->width, fb_page->height, fb_page->line_length); if (xenfb_map_fb(xenfb, xenfb->fb.otherend_id) < 0) return -1;