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
This commit is contained in:
Alexander Volkov 2018-02-06 16:04:20 +01:00 committed by Kim Woelders
parent 56ca24fc9f
commit ca17031280
3 changed files with 150 additions and 44 deletions

View File

@ -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"

View File

@ -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

View File

@ -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 */
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;
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;
if (x_does_shm == 2)
xcb_connection_t *c = XGetXCBConnection(d);
si->shmaddr = NULL;
si->shmseg = xcb_generate_id(c);
si->readOnly = False;
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 (si->shmaddr == NULL)
{
xcb_shm_detach(c, si->shmseg);
}
free(reply);
}
free(error);
if (si->shmaddr)
{
xim->data = si->shmaddr;
if (draw != None)
XShmGetImage(d, draw, xim, x, y, 0xffffffff);
if (x_does_shm == 2)
return xim;
}
else
{
x_does_shm = 0;
}
}
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)
{
/* wait for X to reply and do this */
XSync(d, False);
/* reset the error handler */
XSetErrorHandler(ph);
x_does_shm = 1;
XErrorHandler ph = NULL;
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);
}
/* 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);
}
/* 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);
}