kwo pushed a commit to branch master. http://git.enlightenment.org/legacy/imlib2.git/commit/?id=ca17031280fddf1ba14a5f9d8d89507301d0db26
commit ca17031280fddf1ba14a5f9d8d89507301d0db26 Author: Alexander Volkov <[email protected]> Date: Tue Feb 6 16:04:20 2018 +0100 Add support for MIT-SHM FD-passing Summary: This is more secure way of using shared memory because it's visible only to the X server and the application. Reviewers: kwo Reviewed By: kwo Differential Revision: https://phab.enlightenment.org/D5788 --- configure.ac | 24 ++++++++ src/lib/Makefile.am | 2 +- src/lib/ximage.c | 164 +++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 148 insertions(+), 42 deletions(-) diff --git a/configure.ac b/configure.ac index bc5a8d0..15ab954 100644 --- a/configure.ac +++ b/configure.ac @@ -99,8 +99,31 @@ fi if test "x$have_x" = "xyes"; then AC_DEFINE(BUILD_X11, 1, [enabling X11 support]) + AC_MSG_CHECKING(whether to enable X11 MIT-SHM FD-passing support) + AC_ARG_WITH([x-shm-fd], + [AS_HELP_STRING([--without-x-shm-fd], [Disable X11 MIT-SHM FD-passing support])], + [ + if test "$withval" = no ; then + x_shm_fd=no + else + x_shm_fd=yes + fi + ], + [ x_shm_fd=auto ] + ) + AC_MSG_RESULT($x_shm_fd) + + if test "$x_shm_fd" != no ; then + PKG_CHECK_MODULES(X_SHM_FD, x11-xcb xcb xcb-shm >= 1.9, [ x_shm_fd="yes" ], [ x_shm_fd="no"]) + else + x_shm_fd="no" + fi + if test "$x_shm_fd" = yes ; then + AC_DEFINE(HAVE_X11_SHM_FD, 1, [enabling X11 MIT-SHM FD-passing support]) + fi else have_x="no" + x_shm_fd="no" fi AM_CONDITIONAL(BUILD_X11, test "x$have_x" = "xyes") @@ -443,6 +466,7 @@ echo "Use X86 MMX for speed.....: $mmx" echo "Use AMD64 for speed.......: $amd64" echo echo "Use visibility hiding.....: $enable_visibility_hiding" +echo "Use X MIT-SHM FD-passing..: $x_shm_fd" echo echo echo "Installation Path.........: $prefix" diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 83c734f..4f48310 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -87,7 +87,7 @@ EXTRA_DIST = $(MMX_SRCS) $(AMD64_SRCS) asm_loadimmq.S MY_LIBS = $(FREETYPE_LIBS) $(DLOPEN_LIBS) -lm if BUILD_X11 -MY_LIBS += -lXext -lX11 +MY_LIBS += -lXext -lX11 @X_SHM_FD_LIBS@ endif if BUILD_MMX diff --git a/src/lib/ximage.c b/src/lib/ximage.c index 96327f1..14c145c 100644 --- a/src/lib/ximage.c +++ b/src/lib/ximage.c @@ -3,6 +3,11 @@ #include <X11/Xlib.h> #include <X11/extensions/XShm.h> #include <X11/Xutil.h> +#ifdef HAVE_X11_SHM_FD +#include <X11/Xlib-xcb.h> +#include <xcb/shm.h> +#include <sys/mman.h> +#endif #include <sys/ipc.h> #include <sys/shm.h> @@ -10,6 +15,9 @@ /* global flags */ static signed char x_does_shm = -1; +#ifdef HAVE_X11_SHM_FD +static signed char x_does_shm_fd = 0; +#endif /* static private variables */ static int list_num = 0; @@ -37,10 +45,24 @@ ShmCheck(Display * d) { /* if its there set x_does_shm flag */ if (XShmQueryExtension(d)) - x_does_shm = 2; /* 2: __imlib_ShmGetXImage tests first XShmAttach */ + { +#ifdef HAVE_X11_SHM_FD + int major, minor; + Bool pixmaps; +#endif + x_does_shm = 2; /* 2: __imlib_ShmGetXImage tests first XShmAttach */ +#ifdef HAVE_X11_SHM_FD + if (XShmQueryVersion(d, &major, &minor, &pixmaps)) + { + x_does_shm_fd = (major == 1 && minor >= 2) || major > 1; + } +#endif + } /* clear the flag - no shm at all */ else - x_does_shm = 0; + { + x_does_shm = 0; + } } XImage * @@ -60,55 +82,106 @@ __imlib_ShmGetXImage(Display * d, Visual * v, Drawable draw, int depth, if (!xim) return NULL; - /* get an shm id of this image */ - si->shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, - IPC_CREAT | 0666); - /* if the get succeeds */ - if (si->shmid != -1) +#ifdef HAVE_X11_SHM_FD + if (x_does_shm_fd) { - /* set the params for the shm segment */ + xcb_generic_error_t *error = NULL; + xcb_shm_create_segment_cookie_t cookie; + xcb_shm_create_segment_reply_t *reply; + size_t segment_size = xim->bytes_per_line * xim->height; + + xcb_connection_t *c = XGetXCBConnection(d); + si->shmaddr = NULL; + si->shmseg = xcb_generate_id(c); si->readOnly = False; - si->shmaddr = xim->data = shmat(si->shmid, 0, 0); - /* get the shm addr for this data chunk */ - if (xim->data != (char *)-1) - { - XErrorHandler ph = NULL; - if (x_does_shm == 2) + cookie = xcb_shm_create_segment(c, si->shmseg, segment_size, si->readOnly); + reply = xcb_shm_create_segment_reply(c, cookie, &error); + if (reply) + { + int *fds = reply->nfd == 1 ? xcb_shm_create_segment_reply_fds(c, reply) : NULL; + if (fds) { - /* setup a temporary error handler */ - _x_err = 0; - XSync(d, False); - ph = XSetErrorHandler(TmpXError); + si->shmaddr = mmap(0, segment_size, PROT_READ|PROT_WRITE, + MAP_SHARED, fds[0], 0); + close(fds[0]); + if (si->shmaddr == MAP_FAILED) + si->shmaddr = NULL; } - /* ask X to attach to the shared mem segment */ - XShmAttach(d, si); - if (draw != None) - XShmGetImage(d, draw, xim, x, y, 0xffffffff); - if (x_does_shm == 2) + if (si->shmaddr == NULL) { - /* wait for X to reply and do this */ - XSync(d, False); - /* reset the error handler */ - XSetErrorHandler(ph); - x_does_shm = 1; + xcb_shm_detach(c, si->shmseg); } + free(reply); + } + free(error); - /* if we attached without an error we're set */ - if (_x_err == 0) - return xim; + if (si->shmaddr) + { + xim->data = si->shmaddr; + if (draw != None) + XShmGetImage(d, draw, xim, x, y, 0xffffffff); - /* attach by X failed... must be remote client */ - /* flag shm forever to not work - remote */ + return xim; + } + else + { x_does_shm = 0; - - /* detach */ - shmdt(si->shmaddr); } + } + else +#endif + { + /* get an shm id of this image */ + si->shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, + IPC_CREAT | 0666); + /* if the get succeeds */ + if (si->shmid != -1) + { + /* set the params for the shm segment */ + si->readOnly = False; + si->shmaddr = xim->data = shmat(si->shmid, 0, 0); + /* get the shm addr for this data chunk */ + if (xim->data != (char *)-1) + { + XErrorHandler ph = NULL; - /* get failed - out of shm id's or shm segment too big ? */ - /* remove the shm id we created */ - shmctl(si->shmid, IPC_RMID, 0); + if (x_does_shm == 2) + { + /* setup a temporary error handler */ + _x_err = 0; + XSync(d, False); + ph = XSetErrorHandler(TmpXError); + } + /* ask X to attach to the shared mem segment */ + XShmAttach(d, si); + if (draw != None) + XShmGetImage(d, draw, xim, x, y, 0xffffffff); + if (x_does_shm == 2) + { + /* wait for X to reply and do this */ + XSync(d, False); + /* reset the error handler */ + XSetErrorHandler(ph); + x_does_shm = 1; + } + + /* if we attached without an error we're set */ + if (_x_err == 0) + return xim; + + /* attach by X failed... must be remote client */ + /* flag shm forever to not work - remote */ + x_does_shm = 0; + + /* detach */ + shmdt(si->shmaddr); + } + + /* get failed - out of shm id's or shm segment too big ? */ + /* remove the shm id we created */ + shmctl(si->shmid, IPC_RMID, 0); + } } /* couldnt create SHM image ? */ @@ -123,8 +196,17 @@ __imlib_ShmDestroyXImage(Display * d, XImage * xim, XShmSegmentInfo * si) { XSync(d, False); XShmDetach(d, si); - shmdt(si->shmaddr); - shmctl(si->shmid, IPC_RMID, 0); +#ifdef HAVE_X11_SHM_FD + if (x_does_shm_fd) + { + munmap(si->shmaddr, xim->bytes_per_line * xim->height); + } + else +#endif + { + shmdt(si->shmaddr); + shmctl(si->shmid, IPC_RMID, 0); + } XDestroyImage(xim); } --
