[cairo] [PATCH 2/2] xcb: Use SHM FD-passing if possible
Alexander Volkov
a.volkov at rusbitech.ru
Fri Apr 6 12:33:37 UTC 2018
Shared memory created this way is visible only to the X server
and an application.
- it can used if the X server is running as a non-root user other
than a user an application is running as
- other applications of the same user can't access it
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=90512
Signed-off-by: Alexander Volkov <a.volkov at rusbitech.ru>
---
boilerplate/Makefile.win32.features | 12 ++++
build/Makefile.win32.features | 1 +
build/Makefile.win32.features-h | 3 +
build/configure.ac.features | 1 +
configure.ac | 11 ++++
src/Makefile.win32.features | 16 +++++
src/cairo-xcb-connection-shm.c | 98 ++++++++++++++++++++++-------
src/cairo-xcb-connection.c | 7 ++-
src/cairo-xcb-private.h | 4 +-
9 files changed, 130 insertions(+), 23 deletions(-)
diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index 178d5b650..84df408d1 100644
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@ -79,6 +79,18 @@ enabled_cairo_boilerplate_cxx_sources += $(cairo_boilerplate_xcb_shm_cxx_sources
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_shm_sources)
endif
+supported_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_shm_fd_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_shm_fd_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_xcb_shm_fd_private)
+all_cairo_boilerplate_cxx_sources += $(cairo_boilerplate_xcb_shm_fd_cxx_sources)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_shm_fd_sources)
+ifeq ($(CAIRO_HAS_XCB_SHM_FD_FUNCTIONS),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_shm_fd_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_xcb_shm_fd_private)
+enabled_cairo_boilerplate_cxx_sources += $(cairo_boilerplate_xcb_shm_fd_cxx_sources)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_shm_fd_sources)
+endif
+
unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_qt_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_qt_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_qt_private)
diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features
index b15c4488f..f8a1e441d 100644
--- a/build/Makefile.win32.features
+++ b/build/Makefile.win32.features
@@ -5,6 +5,7 @@ CAIRO_HAS_XLIB_XRENDER_SURFACE=0
CAIRO_HAS_XCB_SURFACE=0
CAIRO_HAS_XLIB_XCB_FUNCTIONS=0
CAIRO_HAS_XCB_SHM_FUNCTIONS=0
+CAIRO_HAS_XCB_SHM_FD_FUNCTIONS=0
CAIRO_HAS_QT_SURFACE=0
CAIRO_HAS_QUARTZ_SURFACE=0
CAIRO_HAS_QUARTZ_FONT=0
diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h
index 5759b48a3..53984bb4c 100644
--- a/build/Makefile.win32.features-h
+++ b/build/Makefile.win32.features-h
@@ -20,6 +20,9 @@ endif
ifeq ($(CAIRO_HAS_XCB_SHM_FUNCTIONS),1)
@echo "#define CAIRO_HAS_XCB_SHM_FUNCTIONS 1" >> $(top_srcdir)/src/cairo-features.h
endif
+ifeq ($(CAIRO_HAS_XCB_SHM_FD_FUNCTIONS),1)
+ @echo "#define CAIRO_HAS_XCB_SHM_FD_FUNCTIONS 1" >> $(top_srcdir)/src/cairo-features.h
+endif
ifeq ($(CAIRO_HAS_QT_SURFACE),1)
@echo "#define CAIRO_HAS_QT_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
endif
diff --git a/build/configure.ac.features b/build/configure.ac.features
index e0a46069c..6c8a8f071 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -405,6 +405,7 @@ AC_DEFUN([CAIRO_REPORT],
echo " EGL functions: $use_egl"
echo " X11-xcb functions: $use_xlib_xcb"
echo " XCB-shm functions: $use_xcb_shm"
+ echo " XCB-shm FD-passing functions: $use_xcb_shm_fd"
echo ""
echo "The following features and utilities:"
echo " cairo-trace: $use_trace"
diff --git a/configure.ac b/configure.ac
index d78b2ed41..8c7fa4267 100644
--- a/configure.ac
+++ b/configure.ac
@@ -182,11 +182,22 @@ CAIRO_ENABLE_FUNCTIONS(xcb_shm, XCB/SHM, auto, [
xcb_shm_REQUIRES="xcb-shm"
PKG_CHECK_MODULES(xcb_shm, $xcb_shm_REQUIRES, ,
[use_xcb_shm="no (requires $xcb_shm http://xcb.freedesktop.org)"])
+
else
use_xcb_shm="no (requires --enable-xcb)"
fi
])
+CAIRO_ENABLE_FUNCTIONS(xcb_shm_fd, XCB/SHM FD-passing, auto, [
+ if test "x$use_xcb_shm" = "xyes"; then
+ xcb_shm_fd_REQUIRES="xcb-shm >= 1.9.3"
+ PKG_CHECK_MODULES(xcb_shm_fd, $xcb_shm_fd_REQUIRES, ,
+ [use_xcb_shm_fd="no (requires $xcb_shm_fd_REQUIRES http://xcb.freedesktop.org)"])
+ else
+ use_xcb_shm_fd="no (requires --enable-xcb-shm)"
+ fi
+])
+
dnl ===========================================================================
CAIRO_ENABLE_SURFACE_BACKEND(qt, Qt, no, [
diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features
index 377d6dd12..163e2507c 100644
--- a/src/Makefile.win32.features
+++ b/src/Makefile.win32.features
@@ -101,6 +101,22 @@ ifeq ($(CAIRO_HAS_XCB_SHM_FUNCTIONS),1)
enabled_cairo_pkgconf += cairo-xcb-shm.pc
endif
+supported_cairo_headers += $(cairo_xcb_shm_fd_headers)
+all_cairo_headers += $(cairo_xcb_shm_fd_headers)
+all_cairo_private += $(cairo_xcb_shm_fd_private)
+all_cairo_cxx_sources += $(cairo_xcb_shm_fd_cxx_sources)
+all_cairo_sources += $(cairo_xcb_shm_fd_sources)
+ifeq ($(CAIRO_HAS_XCB_SHM_FD_FUNCTIONS),1)
+enabled_cairo_headers += $(cairo_xcb_shm_fd_headers)
+enabled_cairo_private += $(cairo_xcb_shm_fd_private)
+enabled_cairo_cxx_sources += $(cairo_xcb_shm_fd_cxx_sources)
+enabled_cairo_sources += $(cairo_xcb_shm_fd_sources)
+endif
+all_cairo_pkgconf += cairo-xcb-shm-fd.pc
+ifeq ($(CAIRO_HAS_XCB_SHM_FD_FUNCTIONS),1)
+enabled_cairo_pkgconf += cairo-xcb-shm-fd.pc
+endif
+
unsupported_cairo_headers += $(cairo_qt_headers)
all_cairo_headers += $(cairo_qt_headers)
all_cairo_private += $(cairo_qt_private)
diff --git a/src/cairo-xcb-connection-shm.c b/src/cairo-xcb-connection-shm.c
index e00377cff..bb73ca9b1 100644
--- a/src/cairo-xcb-connection-shm.c
+++ b/src/cairo-xcb-connection-shm.c
@@ -41,35 +41,86 @@
#include <sys/shm.h>
#include <errno.h>
+#if CAIRO_HAS_XCB_SHM_FD_FUNCTIONS
+#include <sys/mman.h>
+#include <unistd.h>
+#endif
+
cairo_int_status_t
_cairo_xcb_connection_shm_create_segment (cairo_xcb_connection_t *connection,
size_t size,
cairo_bool_t readonly,
cairo_xcb_shm_segment_info_t *shm)
{
- xcb_void_cookie_t cookie;
- xcb_generic_error_t *error;
-
- shm->shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0600);
- if (shm->shmid == -1) {
- return errno == ENOMEM ? CAIRO_STATUS_NO_MEMORY : CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- shm->shm = shmat (shm->shmid, NULL, 0);
- shmctl (shm->shmid, IPC_RMID, NULL);
- if (unlikely (shm->shm == (char *) -1))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- shm->shmseg = _cairo_xcb_connection_get_xid (connection);
- cookie = xcb_shm_attach_checked (connection->xcb_connection, shm->shmseg, shm->shmid, readonly);
- error = xcb_request_check (connection->xcb_connection, cookie);
- if (error != NULL) {
- _cairo_xcb_connection_put_xid (connection, shm->shmseg);
- shmdt (shm->shm);
- free (error);
- return CAIRO_INT_STATUS_UNSUPPORTED;
+#if CAIRO_HAS_XCB_SHM_FD_FUNCTIONS
+ if (connection->flags & CAIRO_XCB_HAS_SHM_FD) {
+ xcb_shm_create_segment_cookie_t cookie;
+ xcb_shm_create_segment_reply_t *reply;
+ xcb_generic_error_t *error;
+ int *fds;
+ int err;
+
+ if (unlikely (size > UINT32_MAX))
+ return CAIRO_STATUS_NO_MEMORY;
+
+ shm->shmseg = _cairo_xcb_connection_get_xid (connection);
+ cookie = xcb_shm_create_segment (connection->xcb_connection, shm->shmseg, size, FALSE);
+ reply = xcb_shm_create_segment_reply (connection->xcb_connection, cookie, &error);
+ if (error) {
+ free (error);
+ _cairo_xcb_connection_put_xid (connection, shm->shmseg);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ fds = xcb_shm_create_segment_reply_fds (connection->xcb_connection, reply);
+ if (reply->nfd != 1) {
+ for (int i = 0; i < reply->nfd; i++)
+ close (fds[i]);
+
+ free (reply);
+ xcb_shm_detach (connection->xcb_connection, shm->shmseg);
+ _cairo_xcb_connection_put_xid (connection, shm->shmseg);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ shm->shm = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0], 0);
+ err = errno;
+ close (fds[0]);
+ free (reply);
+
+ if (shm->shm == MAP_FAILED) {
+ xcb_shm_detach (connection->xcb_connection, shm->shmseg);
+ _cairo_xcb_connection_put_xid (connection, shm->shmseg);
+ return err == ENOMEM ? CAIRO_STATUS_NO_MEMORY : CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ } else
+#endif
+ {
+ xcb_void_cookie_t cookie;
+ xcb_generic_error_t *error;
+
+ shm->shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0600);
+ if (shm->shmid == -1) {
+ return errno == ENOMEM ? CAIRO_STATUS_NO_MEMORY : CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ shm->shm = shmat (shm->shmid, NULL, 0);
+ shmctl (shm->shmid, IPC_RMID, NULL);
+ if (unlikely (shm->shm == (char *) -1))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ shm->shmseg = _cairo_xcb_connection_get_xid (connection);
+ cookie = xcb_shm_attach_checked (connection->xcb_connection, shm->shmseg, shm->shmid, readonly);
+ error = xcb_request_check (connection->xcb_connection, cookie);
+ if (error != NULL) {
+ _cairo_xcb_connection_put_xid (connection, shm->shmseg);
+ shmdt (shm->shm);
+ free (error);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
}
+ shm->size = size;
return CAIRO_INT_STATUS_SUCCESS;
}
@@ -79,6 +130,11 @@ _cairo_xcb_connection_shm_destroy_segment (cairo_xcb_connection_t *connection,
{
xcb_shm_detach (connection->xcb_connection, shm->shmseg);
_cairo_xcb_connection_put_xid (connection, shm->shmseg);
+#if CAIRO_HAS_XCB_SHM_FD_FUNCTIONS
+ if (connection->flags & CAIRO_XCB_HAS_SHM_FD)
+ munmap (shm->shm, shm->size);
+ else
+#endif
shmdt (shm->shm);
}
diff --git a/src/cairo-xcb-connection.c b/src/cairo-xcb-connection.c
index 67e2b11a0..2f7645cbe 100644
--- a/src/cairo-xcb-connection.c
+++ b/src/cairo-xcb-connection.c
@@ -453,12 +453,17 @@ _cairo_xcb_connection_query_shm (cairo_xcb_connection_t *connection)
if (version == NULL)
return;
+ connection->flags |= CAIRO_XCB_HAS_SHM;
+ if ((version->major_version == 1 && version->minor_version >= 2) ||
+ version->major_version > 1)
+ connection->flags |= CAIRO_XCB_HAS_SHM_FD;
+
free (version);
- connection->flags |= CAIRO_XCB_HAS_SHM;
status = _cairo_xcb_connection_shm_create_segment (connection, 0x1000, FALSE, &seg_info);
if (status != CAIRO_INT_STATUS_SUCCESS) {
connection->flags &= ~CAIRO_XCB_HAS_SHM;
+ connection->flags &= ~CAIRO_XCB_HAS_SHM_FD;
return;
}
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index 4e417ddff..8a3b9715a 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -82,6 +82,7 @@ struct _cairo_xcb_shm_segment_info {
int shmid;
uint32_t shmseg;
void *shm;
+ size_t size;
};
struct _cairo_xcb_shm_info {
@@ -271,7 +272,8 @@ enum {
CAIRO_XCB_RENDER_HAS_FILTER_GOOD = 0x0400,
CAIRO_XCB_RENDER_HAS_FILTER_BEST = 0x0800,
- CAIRO_XCB_HAS_SHM = 0x80000000,
+ CAIRO_XCB_HAS_SHM = 0x40000000,
+ CAIRO_XCB_HAS_SHM_FD = 0x80000000,
CAIRO_XCB_RENDER_MASK = CAIRO_XCB_HAS_RENDER |
CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES |
--
2.17.0
More information about the cairo
mailing list