diff --git a/debian/control b/debian/control index 1cbc7700..9902e96d 100644 --- a/debian/control +++ b/debian/control @@ -10,9 +10,10 @@ Build-Depends: libvchan-xen-dev, python3-dev, libpulse-dev, - libxext-dev, libxrandr-dev, libxcb1-dev, + libxcb-util0-dev, + libxcb-shm0-dev, libx11-xcb-dev, libconfig-dev, libpng-dev, @@ -21,8 +22,8 @@ Build-Depends: help2man Standards-Version: 4.1.3 Homepage: https://qubes-os.org/ -#Vcs-Browser: https://github.com/QubesOS/qubes-gui-daemon -#Vcs-Git: https://github.com/QubesOS/qubes-gui-daemon.git +Vcs-Browser: https://github.com/QubesOS/qubes-gui-daemon +Vcs-Git: https://github.com/QubesOS/qubes-gui-daemon.git Package: qubes-gui-daemon Architecture: any diff --git a/gui-common/error.c b/gui-common/error.c index cd809aec..9785a621 100644 --- a/gui-common/error.c +++ b/gui-common/error.c @@ -62,6 +62,9 @@ int dummy_handler(Display * dpy, XErrorEvent * ev) sizeof(buf)); fprintf(stderr, " Minor opcode: %d (%s)\n", ev->minor_code, buf); + } else { + fprintf(stderr, " Minor opcode: %d\n", + ev->minor_code); } /* Provide value information */ diff --git a/gui-daemon/Makefile b/gui-daemon/Makefile index 9b4b4c25..b086ce7e 100644 --- a/gui-daemon/Makefile +++ b/gui-daemon/Makefile @@ -22,7 +22,7 @@ MAKEFLAGS := -rR VCHAN_PKG = $(if $(BACKEND_VMM),vchan-$(BACKEND_VMM),vchan) CC=gcc -pkgs := x11 xext x11-xcb xcb glib-2.0 $(VCHAN_PKG) libpng libnotify libconfig +pkgs := x11 x11-xcb xcb xcb-shm xcb-aux glib-2.0 $(VCHAN_PKG) libpng libnotify libconfig objs := xside.o png.o trayicon.o ../gui-common/double-buffer.o ../gui-common/txrx-vchan.o \ ../gui-common/error.o list.o extra_cflags := -I../include/ -g -O2 -Wall -Wextra -Werror -pie -fPIC \ diff --git a/gui-daemon/trayicon.c b/gui-daemon/trayicon.c index bbcfc678..2256ef47 100644 --- a/gui-daemon/trayicon.c +++ b/gui-daemon/trayicon.c @@ -24,8 +24,10 @@ #include #include #include +#include #include #include "xside.h" +#include /* initialization required for TRAY_BACKGROUND mode */ void init_tray_bg(Ghandles *g) { @@ -45,7 +47,7 @@ void fill_tray_bg_and_update(Ghandles *g, struct windowdata *vm_window, size_t data_sz; int xp, yp; - if (!vm_window->image) { + if (vm_window->shmseg == QUBES_NO_SHM_SEGMENT) { /* TODO: implement screen_window handling */ return; } @@ -77,10 +79,11 @@ void fill_tray_bg_and_update(Ghandles *g, struct windowdata *vm_window, vm_window->image_width, vm_window->image_height, 24); - XShmPutImage(g->display, pixmap, g->context, - vm_window->image, 0, 0, 0, 0, - vm_window->image_width, - vm_window->image_height, 0); + put_shm_image(g, pixmap, vm_window, + 0, 0, + vm_window->image_width, + vm_window->image_height, + 0, 0); XImage *image = XGetImage(g->display, pixmap, 0, 0, w, h, 0xFFFFFFFF, ZPixmap); /* Use top-left corner pixel color as transparency color */ @@ -231,7 +234,7 @@ void tint_tray_and_update(Ghandles *g, struct windowdata *vm_window, uint32_t pixel; double h_ignore, l, s_ignore; - if (!vm_window->image) { + if (vm_window->shmseg == QUBES_NO_SHM_SEGMENT) { /* TODO: implement screen_window handling */ return; } @@ -245,10 +248,11 @@ void tint_tray_and_update(Ghandles *g, struct windowdata *vm_window, vm_window->image_width, vm_window->image_height, 24); - XShmPutImage(g->display, pixmap, g->context, - vm_window->image, 0, 0, 0, 0, - vm_window->image_width, - vm_window->image_height, 0); + put_shm_image(g, pixmap, vm_window, + 0, 0, + vm_window->image_width, + vm_window->image_height, + 0, 0); XImage *image = XGetImage(g->display, pixmap, x, y, w, h, 0xFFFFFFFF, ZPixmap); /* tint image */ diff --git a/gui-daemon/xside.c b/gui-daemon/xside.c index 9fd61311..a3f2ec06 100644 --- a/gui-daemon/xside.c +++ b/gui-daemon/xside.c @@ -22,13 +22,16 @@ /* high level documentation is here: https://www.qubes-os.org/doc/gui/ */ +#define _GNU_SOURCE 1 #include +#include #include #include #include +#include #include #include -#include +#include #include #include #include @@ -45,17 +48,21 @@ #include #include #include -#include #include #include #include +#include #include +#include +#include #include #include #include #include #include #include +#include +#include #include "xside.h" #include "txrx.h" #include "double-buffer.h" @@ -103,12 +110,6 @@ static Ghandles ghandles; #define ignore_result(x) { __typeof__(x) __attribute__((unused)) _ignore=(x);} -/* XShmAttach return value inform only about successful queueing the operation, - * not its execution. Errors during XShmAttach are reported asynchronously with - * registered X11 error handler. - */ -static bool shm_attach_failed = false; - static int (*default_x11_io_error_handler)(Display *dpy); static void inter_appviewer_lock(Ghandles *g, int mode); static void release_mapped_mfns(Ghandles * g, struct windowdata *vm_window); @@ -221,27 +222,25 @@ static int ask_whether_verify_failed(Ghandles * g, const char *cond) abort(); } -#ifdef MAKE_X11_ERRORS_FATAL -/* nothing called from X11 error handler can send X11 requests, so release - * shared memory and simply forget about the image - the gui daemon will exit - * shortly anyway. - */ -static void release_all_shm_no_x11_calls() { - struct genlist *curr; - if (ghandles.log_level > 1) - fprintf(stderr, "release_all_shm_no_x11_calls running\n"); - print_backtrace(); - for (curr = ghandles.wid2windowdata->next; - curr != ghandles.wid2windowdata; curr = curr->next) { - struct windowdata *vm_window = curr->data; - if (vm_window->image) { - vm_window->image = NULL; - shmctl(vm_window->shminfo.shmid, IPC_RMID, 0); - } - } - +static void +qubes_xcb_handler(Ghandles *g, const char *msg, struct windowdata *vm_window, + xcb_generic_error_t *error) { + fprintf(stderr, + "%s failed for window 0x%lx(remote 0x%lx)\n", + msg, + vm_window->local_winid, + vm_window->remote_winid); + XErrorEvent err = { + .type = error->response_type, + .display = g->display, + .error_code = error->error_code, + .resourceid = error->resource_id, + .serial = error->full_sequence, + .request_code = error->major_code, + .minor_code = error->minor_code, + }; + dummy_handler(g->display, &err); } -#endif int x11_error_handler(Display * dpy, XErrorEvent * ev) { @@ -264,21 +263,7 @@ int x11_error_handler(Display * dpy, XErrorEvent * ev) return 0; } - if (ev->request_code == ghandles.shm_major_opcode - && ev->minor_code == X_ShmAttach - && ev->error_code == BadAccess) { - shm_attach_failed = true; - /* shmoverride failed to attach memory region, - * handled in handle_mfndump/handle_window_dump */ - return 0; - } #ifdef MAKE_X11_ERRORS_FATAL - /* The exit(1) below will call release_all_mapped_mfns (registerd with - * atexit(3)), which would try to release window images with XShmDetach. We - * can't send X11 requests in X11 error handler, so clean window images - * without calling to X11. And hope that X server will call XShmDetach - * internally when cleaning windows of disconnected client */ - release_all_shm_no_x11_calls(); exit(1); #endif return 0; @@ -290,14 +275,7 @@ int x11_error_handler(Display * dpy, XErrorEvent * ev) */ static int x11_io_error_handler(Display * dpy) { - /* The default error handler below will call exit(1), which will then call - * release_all_mapped_mfns (registerd with atexit(3)), which would try to - * release window images with XShmDetach. - * When the IO error occurs in X11 it is no longer safe/possible to - * communicate with the X server. Clean window images without calling to - * X11. And hope that X server will call XShmDetach internally when - * cleaning windows of disconnected client */ - release_all_shm_no_x11_calls(); + print_backtrace(); if (default_x11_io_error_handler) default_x11_io_error_handler(dpy); exit(1); @@ -632,17 +610,21 @@ static void mkghandles(Ghandles * g) XWindowAttributes attr; int i; - g->display = XOpenDisplay(NULL); - if (!g->display) { - perror("XOpenDisplay"); - exit(1); - } - if (!(g->cb_connection = XGetXCBConnection(g->display))) { - perror("XGetXCBConnection"); - exit(1); - } + if (!(g->display = XOpenDisplay(NULL))) + err(1, "XOpenDisplay"); + if (!(g->cb_connection = XGetXCBConnection(g->display))) + err(1, "XGetXCBConnection"); + if ((g->xen_dir_fd = open("/dev/xen", O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_RDONLY)) == -1) + err(1, "open /dev/xen"); + if ((g->xen_fd = openat(g->xen_dir_fd, "gntdev", O_PATH|O_CLOEXEC|O_NOCTTY)) == -1) + err(1, "open /dev/xen/gntdev"); g->screen = DefaultScreen(g->display); g->root_win = RootWindow(g->display, g->screen); + g->gc = xcb_generate_id(g->cb_connection); + const xcb_void_cookie_t cookie = check_xcb_void( + xcb_create_gc_aux_checked( + g->cb_connection, g->gc, g->root_win, 0, NULL), + "xcb_create_gc_aux_checked"); if (!XGetWindowAttributes(g->display, g->root_win, &attr)) { fprintf(stderr, "Cannot query window attributes!\n"); exit(1); @@ -653,6 +635,10 @@ static void mkghandles(Ghandles * g) g->clipboard_requested = 0; g->clipboard_xevent_time = 0; intern_global_atoms(g); + if (!g->context || xcb_request_check(g->cb_connection, cookie)) { + fprintf(stderr, "Failed to create global graphics context!\n"); + exit(1); + } if (!XQueryExtension(g->display, "MIT-SHM", &g->shm_major_opcode, &ev_base, &err_base)) fprintf(stderr, "MIT-SHM X extension missing!\n"); @@ -1992,7 +1978,7 @@ static void do_shm_update(Ghandles * g, struct windowdata *vm_window, return; } // now known: untrusted_x and untrusted_y are not negative - if (vm_window->image) { + if (vm_window->shmseg != QUBES_NO_SHM_SEGMENT) { // image_width and image_height are not negative // (checked in handle_mfndump and handle_window_dump) x = min(untrusted_x, vm_window->image_width); @@ -2133,16 +2119,17 @@ static void do_shm_update(Ghandles * g, struct windowdata *vm_window, else if (g->trayicon_mode == TRAY_TINT) tint_tray_and_update(g, vm_window, x, y, w, h); } else { - if (vm_window->image) { - XShmPutImage(g->display, vm_window->local_winid, - g->context, vm_window->image, x, - y, x, y, w, h, 0); - } else if (g->screen_window && g->screen_window->image) { + if (vm_window->shmseg != QUBES_NO_SHM_SEGMENT) { + put_shm_image(g, vm_window->local_winid, vm_window, x, y, w, h, x, y); + } else if (g->screen_window && g->screen_window->shmseg != QUBES_NO_SHM_SEGMENT) { // vm_window->x+x and vm_window->y+y are the position relative to // the screen, while x and y are the position relative to the window - XShmPutImage(g->display, vm_window->local_winid, - g->context, g->screen_window->image, vm_window->x+x, - vm_window->y+y, x, y, w, h, 0); + put_shm_image(g, + vm_window->local_winid, + g->screen_window, + vm_window->x + x, + vm_window->y + y, + w, h, x, y); } /* else no window content to update, but still draw a frame (if needed) */ } @@ -2426,11 +2413,11 @@ static void handle_create(Ghandles * g, XID window) vm_window = (struct windowdata *) calloc(1, sizeof(struct windowdata)); if (!vm_window) { - perror("malloc(vm_window in handle_create)"); + perror("calloc(vm_window in handle_create)"); exit(1); } + vm_window->shmseg = QUBES_NO_SHM_SEGMENT; /* - because of calloc vm_window->image = 0; vm_window->is_mapped = 0; vm_window->local_winid = 0; vm_window->dest = vm_window->src = vm_window->pix = 0; @@ -3165,16 +3152,85 @@ static void inter_appviewer_lock(Ghandles *g, int mode) /* release shared memory connected with given window */ static void release_mapped_mfns(Ghandles * g, struct windowdata *vm_window) { - if (g->invisible || !vm_window->image) + if (g->invisible || vm_window->shmseg == QUBES_NO_SHM_SEGMENT) + return; + check_xcb_void( + xcb_shm_detach(g->cb_connection, vm_window->shmseg), + "xcb_shm_detach"); + vm_window->shmseg = QUBES_NO_SHM_SEGMENT; +} + +static void +qubes_xcb_send_xen_fd(Ghandles *g, + struct windowdata *vm_window, + struct shm_args_hdr *shm_args, + size_t shm_args_len) +{ + if (g->invisible) return; + shm_args->domid = g->domid; + vm_window->shmseg = xcb_generate_id(g->cb_connection); + if (vm_window->shmseg == QUBES_NO_SHM_SEGMENT) { + fputs("xcb_generate_id returned QUBES_NO_SHM_SEGMENT!\n", stderr); + abort(); + } + if (shm_args_len > SHM_ARGS_SIZE) + errx(1, "shm_args_len is %zu, exceeding maximum of %zu", shm_args_len, + (size_t)SHM_ARGS_SIZE); inter_appviewer_lock(g, 1); - g->shm_args->shmid = vm_window->shminfo.shmid; - XShmDetach(g->display, &vm_window->shminfo); - XDestroyImage(vm_window->image); - XSync(g->display, False); + int dup_fd; + switch (shm_args->type) { + case SHM_ARGS_TYPE_MFNS: + if ((dup_fd = fcntl(g->xen_fd, F_DUPFD_CLOEXEC, 3)) < 3) { + assert(dup_fd == -1); + err(1, "fcntl(F_DUPFD_CLOEXEC)"); + } + break; + default: + fputs("internal wrong command type (this is a bug)\n", stderr); + abort(); + case SHM_ARGS_TYPE_GRANT_REFS: + if ((dup_fd = openat(g->xen_dir_fd, "gntdev", O_RDWR|O_CLOEXEC|O_NOCTTY)) == -1) + err(1, "open(\"/dev/xen/gntdev\")"); + struct shm_args_grant_refs *s = + (struct shm_args_grant_refs *)((uint8_t *)shm_args + sizeof(struct shm_args_hdr)); + struct ioctl_gntdev_map_grant_ref *gref = malloc( + s->count * sizeof(struct ioctl_gntdev_grant_ref) + + offsetof(struct ioctl_gntdev_map_grant_ref, refs)); + if (!gref) + err(1, "malloc failed"); + gref->count = s->count; + gref->pad = 0; + gref->index = UINT64_MAX; + for (size_t i = 0; i < s->count; ++i) { + gref->refs[i].domid = g->domid; + gref->refs[i].ref = s->refs[i]; + } + if (ioctl(dup_fd, IOCTL_GNTDEV_MAP_GRANT_REF, gref) != 0) + err(1, "ioctl(IOCTL_GNTDEV_MAP_GRANT_REF)"); + if (gref->index != 0) + fprintf(stderr, + "ioctl(IOCTL_GNTDEV_MAP_GRANT_REF) set index to nonzero value %" PRIu64 "\n", + (uint64_t)gref->index); + s->off = gref->index; + free(gref); + } + memcpy(g->shm_args, shm_args, shm_args_len); + memset(((uint8_t *) g->shm_args) + shm_args_len, 0, + SHM_ARGS_SIZE - shm_args_len); + const xcb_void_cookie_t cookie = + check_xcb_void( + xcb_shm_attach_fd_checked(g->cb_connection, vm_window->shmseg, + dup_fd, true), + "xcb_shm_attach_fd_checked"); + xcb_aux_sync(g->cb_connection); + xcb_generic_error_t *error = xcb_request_check(g->cb_connection, cookie); inter_appviewer_lock(g, 0); - vm_window->image = NULL; - shmctl(vm_window->shminfo.shmid, IPC_RMID, 0); + if (error) { + qubes_xcb_handler(g, "xcb_shm_attach_fd", vm_window, error); + free(error); + vm_window->shmseg = QUBES_NO_SHM_SEGMENT; + } } /* handle VM message: MSG_MFNDUMP @@ -3235,21 +3291,8 @@ static void handle_mfndump(Ghandles * g, struct windowdata *vm_window) shm_args_mfns->off = off; read_data(g->vchan, (char *) &shm_args_mfns->mfns[0], mfns_len); - if (g->invisible) - goto out_free_shm_args; - vm_window->image = - XShmCreateImage(g->display, - DefaultVisual(g->display, g->screen), 24, - ZPixmap, NULL, &vm_window->shminfo, - vm_window->image_width, - vm_window->image_height); - if (!vm_window->image) { - perror("XShmCreateImage"); - exit(1); - } - /* the below sanity check must be AFTER XShmCreateImage, it uses vm_window->image */ if (num_mfn * 4096 < - vm_window->image->bytes_per_line * vm_window->image->height + + vm_window->image_width * vm_window->image_height * 4 + off) { fprintf(stderr, "handle_mfndump for window 0x%x(remote 0x%x)" @@ -3258,44 +3301,7 @@ static void handle_mfndump(Ghandles * g, struct windowdata *vm_window) (int) vm_window->remote_winid, num_mfn); exit(1); } - // temporary shmid; see shmoverride/README - vm_window->shminfo.shmid = - shmget(IPC_PRIVATE, 1, IPC_CREAT | 0700); - if (vm_window->shminfo.shmid < 0) { - perror("shmget"); - exit(1); - } - shm_args->shmid = vm_window->shminfo.shmid; - shm_args->domid = g->domid; - inter_appviewer_lock(g, 1); - memcpy(g->shm_args, shm_args, shm_args_len); - if (shm_args_len < SHM_ARGS_SIZE) { - memset(((uint8_t *) g->shm_args) + shm_args_len, 0, - SHM_ARGS_SIZE - shm_args_len); - } - { - static char dummybuf[100]; - vm_window->shminfo.shmaddr = vm_window->image->data = dummybuf; - } - vm_window->shminfo.readOnly = True; - shm_attach_failed = false; - if (!XShmAttach(g->display, &vm_window->shminfo)) - shm_attach_failed = true; - /* shm_attach_failed can be also set by the X11 error handler */ - XSync(g->display, False); - g->shm_args->shmid = g->cmd_shmid; - inter_appviewer_lock(g, 0); - if (shm_attach_failed) { - fprintf(stderr, - "XShmAttach failed for window 0x%lx(remote 0x%lx)\n", - vm_window->local_winid, - vm_window->remote_winid); - XDestroyImage(vm_window->image); - vm_window->image = NULL; - shmctl(vm_window->shminfo.shmid, IPC_RMID, 0); - } - -out_free_shm_args: + qubes_xcb_send_xen_fd(g, vm_window, shm_args, shm_args_len); free(shm_args); } @@ -3353,11 +3359,9 @@ static void handle_window_dump_body(Ghandles *g, uint32_t wd_type, size_t } } - static void handle_window_dump(Ghandles *g, struct windowdata *vm_window, uint32_t untrusted_len) { struct msg_window_dump_hdr untrusted_wd_hdr; - static char dummybuf[100]; struct shm_args_hdr *shm_args = NULL; size_t shm_args_len = 0, img_data_size = 0; @@ -3393,30 +3397,9 @@ static void handle_window_dump(Ghandles *g, struct windowdata *vm_window, handle_window_dump_body(g, wd_type, untrusted_wd_body_len, &img_data_size, &shm_args, &shm_args_len); - if (g->invisible) - return; - - // temporary shmid; see shmoverride/README - vm_window->shminfo.shmid = - shmget(IPC_PRIVATE, 1, IPC_CREAT | 0700); - if (vm_window->shminfo.shmid < 0) { - perror("shmget failed"); - exit(1); - } - - vm_window->image = - XShmCreateImage(g->display, - DefaultVisual(g->display, g->screen), 24, - ZPixmap, NULL, &vm_window->shminfo, - vm_window->image_width, - vm_window->image_height); - if (!vm_window->image) { - perror("XShmCreateImage"); - exit(1); - } - /* the below sanity check must be AFTER XShmCreateImage, it uses vm_window->image */ - if (img_data_size < (size_t) (vm_window->image->bytes_per_line * - vm_window->image->height)) { + if (img_data_size < (size_t) (vm_window->image_width * + vm_window->image_height * + 4)) { fprintf(stderr, "handle_window_dump: got too small image data size (%zu)" " for window 0x%lx (remote 0x%lx)\n", @@ -3424,32 +3407,7 @@ static void handle_window_dump(Ghandles *g, struct windowdata *vm_window, exit(1); } - shm_args->domid = g->domid; - shm_args->shmid = vm_window->shminfo.shmid; - inter_appviewer_lock(g, 1); - memcpy(g->shm_args, shm_args, shm_args_len); - if (shm_args_len < SHM_ARGS_SIZE) { - memset(((uint8_t *) g->shm_args) + shm_args_len, 0, - SHM_ARGS_SIZE - shm_args_len); - } - vm_window->shminfo.shmaddr = vm_window->image->data = dummybuf; - vm_window->shminfo.readOnly = True; - shm_attach_failed = false; - if (!XShmAttach(g->display, &vm_window->shminfo)) - shm_attach_failed = true; - /* shm_attach_failed can be also set by the X11 error handler */ - XSync(g->display, False); - g->shm_args->shmid = g->cmd_shmid; - inter_appviewer_lock(g, 0); - if (shm_attach_failed) { - fprintf(stderr, - "XShmAttach failed for window 0x%lx(remote 0x%lx)\n", - vm_window->local_winid, - vm_window->remote_winid); - XDestroyImage(vm_window->image); - vm_window->image = NULL; - shmctl(vm_window->shminfo.shmid, IPC_RMID, 0); - } + qubes_xcb_send_xen_fd(g, vm_window, shm_args, shm_args_len); free(shm_args); } @@ -3552,17 +3510,26 @@ static void handle_message(Ghandles * g) } } +/* helper to get a file flag path */ +static char *guid_fs_flag(const char *type, int domid) +{ + static char buf[256]; + snprintf(buf, sizeof(buf), "/run/qubes/guid-%s.%d", + type, domid); + return buf; +} + +/* remove guid_running file at exit */ +static void unset_alive_flag(void) +{ + unlink(guid_fs_flag("running", ghandles.domid)); +} + /* signal handler - connected to SIGTERM */ static void dummy_signal_handler(int UNUSED(x)) { - /* The exit(0) below will call release_all_mapped_mfns (registerd with - * atexit(3)), which would try to release window images with XShmDetach. We - * can't send X11 requests if one is currently being handled. Since signals - * are asynchronous, we don't know that. Clean window images - * without calling to X11. And hope that X server will call XShmDetach - * internally when cleaning windows of disconnected client */ - release_all_shm_no_x11_calls(); - exit(0); + unset_alive_flag(); + _exit(0); } /* signal handler - connected to SIGHUP */ @@ -3592,22 +3559,6 @@ static void print_backtrace(void) } -/* release all windows mapped memory */ -static void release_all_mapped_mfns(void) -{ - struct genlist *curr; - if (ghandles.log_level > 1) - fprintf(stderr, "release_all_mapped_mfns running\n"); - print_backtrace(); - for (curr = ghandles.wid2windowdata->next; - curr != ghandles.wid2windowdata; curr = curr->next) { - struct windowdata *vm_window = curr->data; - /* use ghandles directly, as no other way get it (atexit cannot - * pass argument) */ - release_mapped_mfns(&ghandles, vm_window); - } -} - static void send_xconf(Ghandles * g) { struct msg_xconf xconf; @@ -4259,15 +4210,6 @@ static void parse_config(Ghandles * g) } } -/* helper to get a file flag path */ -static char *guid_fs_flag(const char *type, int domid) -{ - static char buf[256]; - snprintf(buf, sizeof(buf), "/run/qubes/guid-%s.%d", - type, domid); - return buf; -} - static int guid_boot_lock = -1; /* create guid_running file when connected to VM */ @@ -4285,12 +4227,6 @@ static void set_alive_flag(int domid) close(guid_boot_lock); } -/* remove guid_running file at exit */ -static void unset_alive_flag(void) -{ - unlink(guid_fs_flag("running", ghandles.domid)); -} - void vchan_close() { libvchan_close(ghandles.vchan); @@ -4319,7 +4255,6 @@ static void get_boot_lock(int domid) } static void cleanup() { - release_all_mapped_mfns(); XCloseDisplay(ghandles.display); unset_alive_flag(); close(ghandles.inter_appviewer_lock_fd); @@ -4509,7 +4444,7 @@ int main(int argc, char **argv) signal(SIGTERM, dummy_signal_handler); signal(SIGUSR1, dummy_signal_handler); signal(SIGHUP, sighup_signal_handler); - atexit(release_all_mapped_mfns); + atexit(print_backtrace); if (ghandles.kill_on_connect) { kill(ghandles.kill_on_connect, SIGUSR1); diff --git a/gui-daemon/xside.h b/gui-daemon/xside.h index 9ec281d8..17e8bdd4 100644 --- a/gui-daemon/xside.h +++ b/gui-daemon/xside.h @@ -1,5 +1,5 @@ -#ifndef _XSIDE_H -#define _XSIDE_H +#ifndef QUBES_XSIDE_H +#define QUBES_XSIDE_H QUBES_XSIDE_H /* * The Qubes OS Project, http://www.qubes-os.org * @@ -83,9 +83,10 @@ #include #include #include -#include #include #include +#include +#include "util.h" #define QUBES_POLICY_EVAL_SIMPLE_SOCKET ("/etc/qubes-rpc/" QUBES_SERVICE_EVAL_SIMPLE) #define QREXEC_PRELUDE_CLIPBOARD_PASTE (QUBES_SERVICE_EVAL_SIMPLE "+" QUBES_SERVICE_CLIPBOARD_PASTE " dom0 keyword adminvm") @@ -116,8 +117,7 @@ struct windowdata { struct windowdata *parent; /* parent window */ struct windowdata *transient_for; /* transient_for hint for WM, see http://tronche.com/gui/x/icccm/sec-4.html#WM_TRANSIENT_FOR */ int override_redirect; /* see http://tronche.com/gui/x/xlib/window/attributes/override-redirect.html */ - XShmSegmentInfo shminfo; /* temporary shmid; see shmoverride/README */ - XImage *image; /* image with window content */ + xcb_shm_seg_t shmseg; /* X Shared Memory segment, or ((xcb_shm_seg_t)-1) if there is none */ int image_height; /* size of window content, not always the same as window in dom0! */ int image_width; int have_queued_configure; /* have configure request been sent to VM - waiting for confirmation */ @@ -229,13 +229,48 @@ struct _global_handles { char *screensaver_names[MAX_SCREENSAVER_NAMES]; /* WM_CLASS names for windows detected as screensavers */ Cursor *cursors; /* preloaded cursors (using XCreateFontCursor) */ xcb_connection_t *cb_connection; /**< XCB connection */ + xcb_gcontext_t gc; /**< XCB graphics context */ int work_x, work_y, work_width, work_height; /* do not allow a window to go beyond these bounds */ Atom qubes_label, qubes_label_color, qubes_vmname, qubes_vmwindowid, net_wm_icon; bool in_dom0; /* true if we are in dom0, otherwise false */ Atom net_supported; + int xen_fd; /* O_PATH file descriptor to /dev/xen/gntdev */ + int xen_dir_fd; /* file descriptor to /dev/xen */ bool permit_subwindows : 1; /* Permit subwindows */ }; typedef struct _global_handles Ghandles; -#endif /* _XSIDE_H */ +static inline void put_shm_image( + Ghandles *g, + xcb_drawable_t drawable, + struct windowdata *vm_window, + uint16_t src_x, + uint16_t src_y, + uint16_t w, + uint16_t h, + uint16_t dst_x, + uint16_t dst_y) { + check_xcb_void( + xcb_shm_put_image(g->cb_connection, + drawable, + g->gc, + vm_window->image_width, + vm_window->image_height, + src_x, + src_y, + w, + h, + dst_x, + dst_y, + 24, + XCB_IMAGE_FORMAT_Z_PIXMAP, + 0, + vm_window->shmseg, + 0), + "xcb_shm_put_image"); +} + +#define QUBES_NO_SHM_SEGMENT ((xcb_shm_seg_t)-1) + +#endif /* QUBES_XSIDE_H */ diff --git a/include/shm-args.h b/include/shm-args.h index 3e0d0a70..ed4af14e 100644 --- a/include/shm-args.h +++ b/include/shm-args.h @@ -33,23 +33,24 @@ #define SHM_ARGS_SIZE (SHM_ARGS_NUM_PAGES * 4096) struct shm_args_hdr { - uint32_t shmid; uint32_t domid; uint32_t type; }; enum { - SHM_ARGS_TYPE_MFNS, - SHM_ARGS_TYPE_GRANT_REFS + // do not use 0 here, to help catch bugs + SHM_ARGS_TYPE_MFNS = 1000, + SHM_ARGS_TYPE_GRANT_REFS = 2000, }; struct shm_args_mfns { uint32_t count; uint32_t off; - uint32_t mfns[0]; + uint32_t mfns[]; }; struct shm_args_grant_refs { uint32_t count; - uint32_t refs[0]; + uint64_t off; + uint32_t refs[]; }; diff --git a/include/util.h b/include/util.h index 3b47bc0c..a803b837 100644 --- a/include/util.h +++ b/include/util.h @@ -1,5 +1,19 @@ +#ifndef QUBES_GUI_UTIL_H +#define QUBES_GUI_UTIL_H QUBES_GUI_UTIL_H /* Get the size of an array. Error out on pointers. */ #define QUBES_ARRAY_SIZE(x) (0 * sizeof(struct { \ int tried_to_compute_number_of_array_elements_in_a_pointer: \ 1 - 2*__builtin_types_compatible_p(__typeof__(x), __typeof__(&((x)[0]))); \ }) + sizeof(x)/sizeof((x)[0])) + +/* Exit if an XCB request fails */ +static inline xcb_void_cookie_t check_xcb_void( + xcb_void_cookie_t cookie, + const char *msg) { + if (!cookie.sequence) { + perror(msg); + exit(1); + } + return cookie; +} +#endif diff --git a/rpm_spec/gui-daemon.spec.in b/rpm_spec/gui-daemon.spec.in index b644364f..db0d9998 100644 --- a/rpm_spec/gui-daemon.spec.in +++ b/rpm_spec/gui-daemon.spec.in @@ -45,9 +45,11 @@ Requires: socat BuildRequires: python%{python3_pkgversion}-devel BuildRequires: python%{python3_pkgversion}-setuptools BuildRequires: pulseaudio-libs-devel +BuildRequires: pkgconfig(x11) BuildRequires: pkgconfig(x11-xcb) BuildRequires: pkgconfig(xcb) -BuildRequires: libXext-devel +BuildRequires: pkgconfig(xcb-aux) +BuildRequires: pkgconfig(xcb-shm) BuildRequires: libXrandr-devel BuildRequires: libconfig-devel BuildRequires: libpng-devel diff --git a/shmoverride/Makefile b/shmoverride/Makefile index 0dc808a9..854742fb 100644 --- a/shmoverride/Makefile +++ b/shmoverride/Makefile @@ -30,14 +30,14 @@ LIBDIR ?= /usr/lib64 extra_cflags := -g -O2 -I../include/ -fPIC -Wall -Wextra -Werror \ -DBACKEND_VMM_$(BACKEND_VMM) \ -DSHMOVERRIDE_LIB_PATH=\"$(LIBDIR)/qubes-gui-daemon/shmoverride.so\" \ - -I../include -fvisibility=hidden + -I../include -fvisibility=hidden -pthread CC=gcc all: shmoverride.so X-wrapper-qubes shmoverride.so: shmoverride.o ./list.o $(CC) $(CFLAGS) $(extra_cflags) -shared -o shmoverride.so \ - shmoverride.o list.o -ldl -lxenctrl -lxengnttab + shmoverride.o list.o -ldl -lxenctrl -lxengnttab -Wl,-Bsymbolic vpath %.c ../common diff --git a/shmoverride/README b/shmoverride/README index ee6bcf77..04f8cf30 100644 --- a/shmoverride/README +++ b/shmoverride/README @@ -1,26 +1,22 @@ The shmoverride.so library is supposed to be loaded by Xorg server -(via LD_PRELOAD). It intercepts the shmat, shmdt and shmctl glibc calls, so -that when XShmAttach is called (by qubes_guid) with a "magic" argument, then -instead of attaching regular shared memory, memory from a foreign domain is -attached via xc_map_foreign_pages. This mechanism is used to map composition +(via LD_PRELOAD). It intercepts the mmap, munmap, and fstat glibc calls, so +that when xcb_shm_attach_fd is called (by qubes_guid) with a file descriptor +pointing to /dev/xen/gntdev, then instead of attaching regular shared memory, +memory from a foreign domain is attached via xc_map_foreign_pages or +xengntdev_map_domain_grant_refs. This mechanism is used to map composition buffers from a foreign domain into Xorg server. During its init, shmoverride.so creates a shared memory segment (cmd_pages) and writes its shmid to /var/run/qubes/shm.id.$DISPLAY. All instances of qubes_guid map this segment and communicate with shmoverride.so code by setting its fields. When qubes_guid wants its -XShmAttach(...synth_shmid...) call to be handled by shmoverride.so, it sets the -"shmid" field in the cmd_pages shared memory segment to synth_shmid just -before calling XShmAttach. Function shmat (implemented in shmoverride.so) -checks whether first argument of shmat is equal to cmd_pages->shmid, and if -so, calls xc_map_foreign_pages properly (if not, just calls real shmat). -Other fields in cmd_pages describe which frames are supposed to be mapped -and from which domain. - Somewhat unfortunately, the Xorg server tracks the already attached shmids. -Therefore, it is not possible to pass the same "magic" value of synth_shmid -to XShmAttach(...synth_shmid...). Before each XShmAttach, qubes_guid creates -a corresponding real shared memory segment, sets cmd_pages->shmid to it, and -then executes XShmAttach. This segment is destroyed when the corresponding -backing memory for the composition buffer is released, such as when the window -is resized or closed. Keeping this additional otherwise-unused segment around -for the whole life of the actual inter-domain shared-memory being used is -necessary in order to prevent X from getting confused by shmid reuse. +xcb_shm_attach_fd(...xen_fd...) call to be handled by shmoverride.so, it passes +a file descriptor pointing to /dev/xen/gntdev. fstat (implemented in +shmoverride.so) checks whether it was passed a file descriptor to +/dev/xen/gntdev, and if so, sets st_size in the returned `struct stat` to the +the size memory buffer to map. The shmoverride.so implementation of mmap() +calls fstat() on its fifth argument, and checks the st_dev, st_ino, and st_rdev +fields to determine if a file descriptor to /dev/xen/gntdev was passed. If so, +it uses cmd_pages to determine which frames or grant pages should be mapped and +from which domain. The munmap() implementation checks if the address is one +that shmoverride.so had previously mapped, and if so, calls the appropriate Xen +API functions to release the memory. diff --git a/shmoverride/shmoverride.c b/shmoverride/shmoverride.c index 0f2d99bd..b3c93ed4 100644 --- a/shmoverride/shmoverride.c +++ b/shmoverride/shmoverride.c @@ -23,78 +23,90 @@ #define _GNU_SOURCE 1 #define XC_WANT_COMPAT_MAP_FOREIGN_API -#include #include +#include #include #include +#include +#include + +#include +#include +#include #include #include -#include -#include -#include -#include #include -#include -#include #include #include + +#include +#include +#ifdef NDEBUG +# error must enable assertions +#endif #include -#include "list.h" #include "shm-args.h" #include -static void *(*real_shmat) (int shmid, const void *shmaddr, int shmflg); -static int (*real_shmdt) (const void *shmaddr); -static int (*real_shmctl) (int shmid, int cmd, struct shmid_ds * buf); +#define QUBES_STRINGIFY(x) QUBES_STRINGIFY_(x) +#define QUBES_STRINGIFY_(x) #x + +#ifdef _STAT_VER +# define FSTAT __fxstat +# define FSTAT64 __fxstat64 +# define VER_ARG int ver, +# define VER _STAT_VER, +#else +# define FSTAT fstat +# define FSTAT64 fstat64 +# define VER_ARG +# define VER +#endif + +#define ASM_DEF(ret, name, ...) \ + __attribute__((visibility("default"))) \ + ret name(__VA_ARGS__) __asm__(QUBES_STRINGIFY_(name)); \ + __attribute__((visibility("default"))) \ + ret name(__VA_ARGS__) + +static void *(*real_mmap)(void *shmaddr, size_t len, int prot, int flags, + int fd, off_t offset); +static int (*real_munmap) (void *shmaddr, size_t len); +static int (*real_fstat64) (VER_ARG int fd, struct stat64 *buf); +static int (*real_fstat)(VER_ARG int fd, struct stat *buf); + +static struct stat global_buf; +static int gntdev_fd = -1; static int local_shmid = 0xabcdef; static struct shm_args_hdr *shm_args = NULL; -static struct genlist *addr_list; #ifdef XENCTRL_HAS_XC_INTERFACE static xc_interface *xc_hnd; #else static int xc_hnd; #endif static xengnttab_handle *xgt; -static int list_len; static char __shmid_filename[SHMID_FILENAME_LEN]; static char *shmid_filename = NULL; static int idfd = -1; static char display_str[SHMID_DISPLAY_MAXLEN+1] = ""; -struct mfns_info { - uint32_t count; - uint32_t off; -}; - -struct grant_refs_info { - uint32_t count; -}; - -struct info { - uint32_t type; - union { - struct mfns_info mfns; - struct grant_refs_info grant; - } u; -}; - -static uint8_t *shmat_mfns(struct shm_args_hdr *shm_args, struct info *info) { +static uint8_t *mmap_mfns(struct shm_args_hdr *shm_args) { uint8_t *map; xen_pfn_t *pfntable; uint32_t i; struct shm_args_mfns *shm_args_mfns = (struct shm_args_mfns *) ( ((uint8_t *) shm_args) + sizeof(struct shm_args_hdr)); - pfntable = alloca(sizeof(xen_pfn_t) * shm_args_mfns->count); + pfntable = calloc(sizeof(xen_pfn_t), shm_args_mfns->count); + if (!pfntable) + return NULL; for (i = 0; i < shm_args_mfns->count; i++) pfntable[i] = shm_args_mfns->mfns[i]; - info->u.mfns.count = shm_args_mfns->count; - info->u.mfns.off = shm_args_mfns->off; - map = xc_map_foreign_pages(xc_hnd, shm_args->domid, PROT_READ, pfntable, shm_args_mfns->count); + free(pfntable); if (map == NULL) return NULL; @@ -103,134 +115,116 @@ static uint8_t *shmat_mfns(struct shm_args_hdr *shm_args, struct info *info) { return map; } -static uint8_t *shmat_grant_refs(struct shm_args_hdr *shm_args, - struct info *info) { - uint8_t *map; +static uint8_t *mmap_grant_refs(void *shmaddr, + int fd, + size_t len, + struct shm_args_hdr *shm_args) { struct shm_args_grant_refs *shm_args_grant = (struct shm_args_grant_refs *) ( ((uint8_t *) shm_args) + sizeof(struct shm_args_hdr)); - info->u.grant.count = shm_args_grant->count; - - map = xengnttab_map_domain_grant_refs(xgt, - shm_args_grant->count, - shm_args->domid, - &shm_args_grant->refs[0], - PROT_READ); - - return map; -} - -__attribute__((visibility("default"))) -void *shmat(int shmid, const void *shmaddr, int shmflg) -{ - uint8_t *fakeaddr = NULL; - struct info *info; - - if (!shm_args || (uint32_t)shmid != shm_args->shmid) - return real_shmat(shmid, shmaddr, shmflg); - - info = calloc(1, sizeof(struct info)); - if (info == NULL) - return MAP_FAILED; - - switch (shm_args->type) { - case SHM_ARGS_TYPE_MFNS: - fakeaddr = shmat_mfns(shm_args, info); - break; - case SHM_ARGS_TYPE_GRANT_REFS: - fakeaddr = shmat_grant_refs(shm_args, info); - break; - default: - errno = EINVAL; - } - info->type = shm_args->type; - - if (fakeaddr == NULL) { - free(info); - // errno set by shmat_* - return MAP_FAILED; - } - - list_insert(addr_list, (long) fakeaddr, info); - list_len++; - return fakeaddr; -} - -static int shmdt_mfns(void *map, struct info *info) { - return munmap(map - info->u.mfns.off, info->u.mfns.count * XC_PAGE_SIZE); -} - -static int shmdt_grant_refs(void *map, struct info *info) { - return xengnttab_unmap(xgt, map, info->u.grant.count); -} - -__attribute__((visibility("default"))) -int shmdt(const void *shmaddr) -{ - void *addr = (void *) shmaddr; // drop const qualifier - struct genlist *item = list_lookup(addr_list, (long) addr); - struct info *info; - int rc; - if (!item) - return real_shmdt(shmaddr); - - info = item->data; - switch (info->type) { - case SHM_ARGS_TYPE_MFNS: - rc = shmdt_mfns(addr, info); - break; - case SHM_ARGS_TYPE_GRANT_REFS: - rc = shmdt_grant_refs(addr, info); - break; - default: - errno = EINVAL; - rc = -1; - } - - list_remove(item); - list_len--; - return rc; + return real_mmap(shmaddr, len, PROT_READ, MAP_SHARED, fd, shm_args_grant->off); } static size_t shm_segsz_mfns(struct shm_args_hdr *shm_args) { struct shm_args_mfns *shm_args_mfns = (struct shm_args_mfns *) ( ((uint8_t *) shm_args) + sizeof(struct shm_args_hdr)); - + if (shm_args_mfns->count > MAX_MFN_COUNT) + return 0; // this is considered an error return shm_args_mfns->count * XC_PAGE_SIZE - shm_args_mfns->off; } static size_t shm_segsz_grant_refs(struct shm_args_hdr *shm_args) { struct shm_args_grant_refs *shm_args_grant = (struct shm_args_grant_refs *) ( ((uint8_t *) shm_args) + sizeof(struct shm_args_hdr)); - + if (shm_args_grant->count > MAX_GRANT_REFS_COUNT) + return 0; // this is considered an error return shm_args_grant->count * XC_PAGE_SIZE; } -__attribute__((visibility("default"))) -int shmctl(int shmid, int cmd, struct shmid_ds *buf) +_Thread_local static bool in_shmoverride = false; +ASM_DEF(void *, mmap, + void *shmaddr, size_t len, int prot, int flags, + int fd, off_t offset) { - size_t segsz = 0; + struct stat64 buf; + if (0) { + // These are purely for type-checking by the C compiler; they are not + // executed at runtime + real_mmap = mmap64; + real_mmap = mmap; + real_fstat64 = FSTAT64; + real_fstat = FSTAT; + } - if (!shm_args || (uint32_t)shmid != shm_args->shmid || cmd != IPC_STAT) - return real_shmctl(shmid, cmd, buf); +#if defined MAP_ANON && defined MAP_ANONYMOUS && (MAP_ANONYMOUS) != (MAP_ANON) +# error header bug (def mismatch) +#endif +#ifndef MAP_ANON +# define MAP_ANON 0 +#endif +#ifndef MAP_ANONYMOUS +# define MAP_ANONYMOUS 0 +#endif + if ((flags & (MAP_ANON|MAP_ANONYMOUS)) || in_shmoverride) + return real_mmap(shmaddr, len, prot, flags, fd, offset); + + if (real_fstat64( +#ifdef _STAT_VER + _STAT_VER, +#endif + fd, &buf)) + return MAP_FAILED; + + if (!S_ISCHR(buf.st_mode) || + buf.st_dev != global_buf.st_dev || + buf.st_ino != global_buf.st_ino || + buf.st_rdev != global_buf.st_rdev) { + return real_mmap(shmaddr, len, prot, flags, fd, offset); + } + + if ((prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) != PROT_READ || + flags != MAP_SHARED || + offset != 0) { + errno = EINVAL; + return MAP_FAILED; + } + + in_shmoverride = true; + uint8_t *fakeaddr = MAP_FAILED; switch (shm_args->type) { case SHM_ARGS_TYPE_MFNS: - segsz = shm_segsz_mfns(shm_args); + if (len == shm_segsz_mfns(shm_args)) + fakeaddr = mmap_mfns(shm_args); + else + errno = EINVAL; break; case SHM_ARGS_TYPE_GRANT_REFS: - segsz = shm_segsz_grant_refs(shm_args); + if (len == shm_segsz_grant_refs(shm_args)) + fakeaddr = mmap_grant_refs(shmaddr, fd, len, shm_args); + else + errno = EINVAL; break; default: errno = EINVAL; - return -1; } + if (!fakeaddr) + fakeaddr = MAP_FAILED; + in_shmoverride = false; + return fakeaddr; +} - memset(&buf->shm_perm, 0, sizeof(buf->shm_perm)); - buf->shm_perm.mode = 0666; - buf->shm_segsz = segsz; +__attribute__((alias("mmap"))) ASM_DEF(void *, mmap64, + void *shmaddr, size_t len, int prot, int flags, + int fd, off_t offset); - return 0; +ASM_DEF(int, munmap, void *addr, size_t len) +{ + if (len > SIZE_MAX - XC_PAGE_SIZE) + abort(); + const uintptr_t addr_int = (uintptr_t)addr; + const uintptr_t rounded_addr = addr_int & ~(uintptr_t)(XC_PAGE_SIZE - 1); + return real_munmap((void *)rounded_addr, len + (addr_int - rounded_addr)); } int get_display(void) @@ -293,20 +287,87 @@ int get_display(void) return 0; } +static int assign_off(off_t *off) { + size_t s; + switch (shm_args->type) { + case SHM_ARGS_TYPE_MFNS: + s = shm_segsz_mfns(shm_args); + break; + case SHM_ARGS_TYPE_GRANT_REFS: + s = shm_segsz_grant_refs(shm_args); + break; + default: + s = 0; + } + if (s) { + *off = (off_t)s; + return 0; + } else { + errno = EINVAL; + return -1; + } +} + +#define STAT(id) \ +ASM_DEF(int, f ## id, int filedes, struct id *buf) { \ + int res = real_f ## id(VER filedes, buf); \ + if (res || \ + !S_ISCHR(buf->st_mode) || \ + buf->st_dev != global_buf.st_dev || \ + buf->st_ino != global_buf.st_ino || \ + buf->st_rdev != global_buf.st_rdev) \ + return res; \ + return assign_off(&buf->st_size); \ +} +STAT(stat) +STAT(stat64) +#undef STAT + +#ifdef _STAT_VER +#define STAT(id) \ +ASM_DEF(int, __fx ## id, int ver, int filedes, struct id *buf) { \ + if (ver != _STAT_VER) { \ + fprintf(stderr, \ + "Wrong _STAT_VER: got %d, expected %d, libc has incompatibly changed\n", \ + ver, _STAT_VER); \ + abort(); \ + } \ + return f ## id(filedes, buf); \ +} +STAT(stat) +STAT(stat64) +#undef STAT +#endif + int __attribute__ ((constructor)) initfunc(void) { int len; char idbuf[20]; unsetenv("LD_PRELOAD"); fprintf(stderr, "shmoverride constructor running\n"); - real_shmat = dlsym(RTLD_NEXT, "shmat"); - real_shmctl = dlsym(RTLD_NEXT, "shmctl"); - real_shmdt = dlsym(RTLD_NEXT, "shmdt"); - if (!real_shmat || !real_shmctl || !real_shmdt) { - perror("shmoverride: missing shm API"); + dlerror(); + if (!(real_mmap = dlsym(RTLD_NEXT, "mmap64"))) { + fprintf(stderr, "shmoverride: no mmap64?: %s", dlerror()); + abort(); + } else if (!(real_fstat = dlsym(RTLD_NEXT, QUBES_STRINGIFY(FSTAT)))) { + fprintf(stderr, "shmoverride: no " QUBES_STRINGIFY(FSTAT) "?: %s", dlerror()); + abort(); + } else if (!(real_fstat64 = dlsym(RTLD_NEXT, QUBES_STRINGIFY(FSTAT64)))) { + fprintf(stderr, "shmoverride: no " QUBES_STRINGIFY(FSTAT64) "?: %s", dlerror()); + abort(); + } else if (!(real_munmap = dlsym(RTLD_NEXT, "munmap"))) { + fprintf(stderr, "shmoverride: no munmap?: %s", dlerror()); + abort(); + } else if ((gntdev_fd = open("/dev/xen/gntdev", O_PATH | O_CLOEXEC | O_NOCTTY)) == -1) { + perror("open /dev/xen/gntdev"); + goto cleanup; + } else if (real_fstat(VER gntdev_fd, &global_buf)) { + perror("stat /dev/xen/gntdev"); + goto cleanup; + } else if (!S_ISCHR(global_buf.st_mode)) { + fprintf(stderr, "/dev/xen/gntdev is not a character special file"); goto cleanup; } - addr_list = list_new(); #ifdef XENCTRL_HAS_XC_INTERFACE xc_hnd = xc_interface_open(NULL, NULL, 0); if (!xc_hnd) { @@ -364,12 +425,11 @@ int __attribute__ ((constructor)) initfunc(void) shmid_filename, strerror(errno)); goto cleanup; } - shm_args = real_shmat(local_shmid, 0, 0); + shm_args = shmat(local_shmid, 0, 0); if (!shm_args) { - perror("real_shmat"); + perror("shmat"); goto cleanup; } - shm_args->shmid = local_shmid; return 0; cleanup: @@ -389,6 +449,10 @@ int __attribute__ ((constructor)) initfunc(void) close(idfd); idfd = -1; } + if (gntdev_fd >= 0) { + close(gntdev_fd); + gntdev_fd = -1; + } if (shmid_filename) { unlink(shmid_filename); shmid_filename = NULL; @@ -403,9 +467,10 @@ int __attribute__ ((destructor)) descfunc(void) assert(shmid_filename); assert(idfd >= 0); - real_shmdt(shm_args); - real_shmctl(local_shmid, IPC_RMID, 0); + shmdt(shm_args); + shmctl(local_shmid, IPC_RMID, 0); close(idfd); + close(gntdev_fd); unlink(shmid_filename); }