Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend shmoverride init config #152

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ selinux_policies ::= qubes-gui-daemon.pp

all_targets := gui-daemon/qubes-guid gui-daemon/qubes-guid.1 \
shmoverride/shmoverride.so \
shmoverride/X-wrapper-qubes pulse/pacat-simple-vchan \
shmoverride/X-wrapper-qubes \
shmoverride/Xwayland-wrapper \
pulse/pacat-simple-vchan \
screen-layout-handler/watch-screen-layout-changes


Expand All @@ -52,6 +54,9 @@ shmoverride/shmoverride.so:
shmoverride/X-wrapper-qubes:
(cd shmoverride; $(MAKE) X-wrapper-qubes)

shmoverride/Xwayland-wrapper:
(cd shmoverride; $(MAKE) Xwayland-wrapper)

pulse/pacat-simple-vchan:
$(MAKE) -C pulse pacat-simple-vchan

Expand All @@ -67,6 +72,7 @@ install:
install -D pulse/pacat-simple-vchan $(DESTDIR)/usr/bin/pacat-simple-vchan
install -D shmoverride/X-wrapper-qubes $(DESTDIR)/usr/bin/X-wrapper-qubes
install -D shmoverride/shmoverride.so $(DESTDIR)$(LIBDIR)/qubes-gui-daemon/shmoverride.so
install -D shmoverride/Xwayland-wrapper $(DESTDIR)/usr/libexec/qubes/wrappers/Xwayland
install -D -m 0644 gui-daemon/guid.conf $(DESTDIR)/etc/qubes/guid.conf
install -D gui-daemon/qubes-localgroup.sh $(DESTDIR)/etc/X11/xinit/xinitrc.d/qubes-localgroup.sh
install -D -m 0644 common/90-default-gui-daemon.policy $(DESTDIR)/etc/qubes/policy.d/90-default-gui-daemon.policy
Expand Down
1 change: 1 addition & 0 deletions debian/qubes-gui-daemon.install
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
usr/bin/X.qubes
usr/bin/qubes-guid
usr/libexec/qubes/watch-screen-layout-changes
usr/libexec/qubes/wrappers/Xwayland
usr/share/man/man1/qubes-guid.1
usr/lib/*/qubes-gui-daemon/shmoverride.so
usr/lib/qubes/icon-receiver
Expand Down
1 change: 1 addition & 0 deletions rpm_spec/gui-daemon.spec.in
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ rm -f %{name}-%{version}
/etc/xdg/autostart/qubes-icon-receiver.desktop
/etc/X11/xinit/xinitrc.d/qubes-localgroup.sh
/usr/libexec/qubes/watch-screen-layout-changes
/usr/libexec/qubes/wrappers/Xwayland
/usr/lib/qubes/icon-receiver
%config %{_sysconfdir}/qubes-rpc/qubes.WindowIconUpdater
%config %{_sysconfdir}/qubes/rpc-config/qubes.WindowIconUpdater
Expand Down
2 changes: 1 addition & 1 deletion shmoverride/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
X_wrapper_qubes
shmoverride.so

Xwayland-wrapper
7 changes: 5 additions & 2 deletions shmoverride/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ extra_cflags := -g -O2 -I../include/ -fPIC -Wall -Wextra -Werror \
-I../include -fvisibility=hidden -pthread
CC=gcc

all: shmoverride.so X-wrapper-qubes
all: shmoverride.so X-wrapper-qubes Xwayland-wrapper

shmoverride.so: shmoverride.o ./list.o
$(CC) $(CFLAGS) $(extra_cflags) -shared -o shmoverride.so \
Expand All @@ -43,8 +43,11 @@ vpath %.c ../common

X-wrapper-qubes: X-wrapper-qubes.o

Xwayland-wrapper: Xwayland-wrapper.in
sed -e "s,@SHMOVERRIDE_LIB_PATH@,$(LIBDIR)/qubes-gui-daemon/shmoverride.so," < $< > $@

clean:
rm -f ./*~ ./*.o shmoverride.so X-wrapper-qubes
rm -f ./*~ ./*.o shmoverride.so X-wrapper-qubes Xwayland-wrapper

%.o: %.c Makefile
$(CC) -MD -MP -MF [email protected] -c -o $@ $(extra_cflags) $(CFLAGS) $<
Expand Down
7 changes: 7 additions & 0 deletions shmoverride/README
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,10 @@ 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.


The LD_PRELOAD can be used in two ways:
1. Set directly for the Xorg/Xwayland process. For this, the package provides convenient wrappers:
- /usr/bin/X for Xorg
- /usr/libexec/qubes/wrappers/Xwayland for Xwayland (can be used by prepending /usr/libexec/qubes/wrappers to PATH for the wayland compositor process)
2. Set for some parent process and use SHMOVERRIDE_PROGLIST="Xorg Xwayland" (space separated list of program basenames) to select which process should be affected.
4 changes: 4 additions & 0 deletions shmoverride/Xwayland-wrapper.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh

export PATH="${PATH#*/wrappers:}"
exec env LD_PRELOAD="@SHMOVERRIDE_LIB_PATH@" Xwayland "$@"
80 changes: 67 additions & 13 deletions shmoverride/shmoverride.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ 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 int try_init(void);

static struct stat global_buf;
static int gntdev_fd = -1;

Expand All @@ -84,7 +86,7 @@ static int xc_hnd;
static xengnttab_handle *xgt;
static char __shmid_filename[SHMID_FILENAME_LEN];
static char *shmid_filename = NULL;
static int idfd = -1, display = -1;
static int idfd = -1, display = -1, init_called = 0;

static uint8_t *mmap_mfns(struct shm_args_hdr *shm_args) {
uint8_t *map;
Expand Down Expand Up @@ -151,6 +153,8 @@ ASM_DEF(void *, mmap,
real_fstat = FSTAT;
}

try_init();

#if defined MAP_ANON && defined MAP_ANONYMOUS && (MAP_ANONYMOUS) != (MAP_ANON)
# error header bug (def mismatch)
#endif
Expand Down Expand Up @@ -217,6 +221,9 @@ ASM_DEF(int, munmap, void *addr, size_t len)
{
if (len > SIZE_MAX - XC_PAGE_SIZE)
abort();

try_init();

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));
Expand Down Expand Up @@ -350,7 +357,7 @@ static bool parse_display_name(const char *const ptr, int *display_num)
return true;
}

static int get_display(void)
static int get_display(const char *progname_allowlist)
{
ssize_t res;
int fd, rc = -1, display = 0;
Expand All @@ -369,6 +376,7 @@ static int get_display(void)
return rc;
}

bool argv0 = progname_allowlist != NULL;
bool skip = true; /* Skip argv[0] (the program name) */
while(true) {
errno = 0;
Expand All @@ -382,6 +390,35 @@ static int get_display(void)
size_t length = (size_t)res;
assert(ptr && ptr[length] == '\0');

if (argv0) {
char *current_item, *next_item;
char *allowlist_copy = strdup(progname_allowlist);
char *progname = strrchr(ptr, '/');

if (!allowlist_copy) {
perror("allowlist copy");
goto cleanup;
}

if (progname)
/* skip '/' */
progname++;
else
progname = ptr;

next_item = allowlist_copy;
while ((current_item = strsep(&next_item, " ")) != NULL) {
if (strcmp(current_item, progname) == 0)
break;
}
free(allowlist_copy);
/* abort if not found */
if (!current_item) {
fprintf(stderr, "skipping shmoverride in %s\n", progname);
goto cleanup;
}
}

/*
* Skip option arguments. Some options take more than one argument,
* but the extra arguments are always optional and display names
Expand Down Expand Up @@ -438,6 +475,7 @@ static int assign_off(off_t *off) {

#define STAT(id) \
ASM_DEF(int, f ## id, int filedes, struct id *buf) { \
try_init(); \
int res = real_f ## id(VER filedes, buf); \
if (res || \
!S_ISCHR(buf->st_mode) || \
Expand All @@ -454,6 +492,7 @@ STAT(stat64)
#ifdef _STAT_VER
#define STAT(id) \
ASM_DEF(int, __fx ## id, int ver, int filedes, struct id *buf) { \
try_init(); \
if (ver != _STAT_VER) { \
fprintf(stderr, \
"Wrong _STAT_VER: got %d, expected %d, libc has incompatibly changed\n", \
Expand All @@ -467,9 +506,13 @@ STAT(stat64)
#undef STAT
#endif

int __attribute__ ((constructor)) initfunc(void)
static int try_init(void)
{
unsetenv("LD_PRELOAD");
// Ideally it is being called in constructor, if something is calling this before
// constructor - we're assuming it is not multi-threaded code.
if (__builtin_expect(init_called, 1)) return 0;
init_called = 1;

fprintf(stderr, "shmoverride constructor running\n");
dlerror();
if (!(real_mmap = dlsym(RTLD_NEXT, "mmap64"))) {
Expand All @@ -484,7 +527,14 @@ int __attribute__ ((constructor)) initfunc(void)
} else if (!(real_munmap = dlsym(RTLD_NEXT, "munmap"))) {
fprintf(stderr, "shmoverride: no munmap?: %s\n", dlerror());
abort();
} else if ((gntdev_fd = open("/dev/xen/gntdev", O_PATH | O_CLOEXEC | O_NOCTTY)) == -1) {
}

if ((display = get_display(getenv("SHMOVERRIDE_PROGLIST"))) < 0)
goto cleanup;

unsetenv("LD_PRELOAD");

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)) {
Expand All @@ -494,6 +544,7 @@ int __attribute__ ((constructor)) initfunc(void)
fprintf(stderr, "/dev/xen/gntdev is not a character special file");
goto cleanup;
}

#ifdef XENCTRL_HAS_XC_INTERFACE
xc_hnd = xc_interface_open(NULL, NULL, 0);
if (!xc_hnd) {
Expand All @@ -511,32 +562,31 @@ int __attribute__ ((constructor)) initfunc(void)
goto cleanup; // Allow it to run when not under Xen.
}

if ((display = get_display()) < 0)
goto cleanup;

if ((unsigned int)snprintf(__shmid_filename, sizeof __shmid_filename,
SHMID_FILENAME_PREFIX "%d", display) >= sizeof __shmid_filename) {
fputs("snprintf() failed!\n", stderr);
abort();
}
shmid_filename = __shmid_filename;
fprintf(stderr, "shmoverride: running with shm file %s\n", shmid_filename);
fprintf(stderr, "shmoverride: running with shm file %s\n", __shmid_filename);

/* Try to lock the shm.id file (don't rely on whether it exists, a previous
* process might have crashed).
*/
idfd = open(shmid_filename, O_RDWR | O_CLOEXEC | O_CREAT | O_NOCTTY, 0600);
idfd = open(__shmid_filename, O_RDWR | O_CLOEXEC | O_CREAT | O_NOCTTY, 0600);
if (idfd < 0) {
fprintf(stderr, "shmoverride opening %s: %s\n",
shmid_filename, strerror(errno));
__shmid_filename, strerror(errno));
goto cleanup;
}
if (flock(idfd, LOCK_EX | LOCK_NB) < 0) {
fprintf(stderr, "shmoverride flock %s: %s\n",
shmid_filename, strerror(errno));
__shmid_filename, strerror(errno));
/* There is probably an alive process holding the file, give up. */
goto cleanup;
}
/* Save shmid file for cleanup only after taking the lock */
shmid_filename = __shmid_filename;

if (ftruncate(idfd, SHM_ARGS_SIZE) < 0) {
perror("shmoverride ftruncate");
goto cleanup;
Expand Down Expand Up @@ -581,6 +631,10 @@ int __attribute__ ((constructor)) initfunc(void)
shm_args = NULL;
return 0;
}
int __attribute__ ((constructor)) initfunc(void)
{
return try_init();
}

int __attribute__ ((destructor)) descfunc(void)
{
Expand Down