added sandbox options to zathurarc

This commit is contained in:
valoq 2018-02-22 14:28:22 +01:00
parent c0bdd41630
commit 3f983e7ae2
Failed to generate hash of commit
7 changed files with 136 additions and 290 deletions

4
README
View file

@ -13,6 +13,7 @@ check (for tests)
intltool
libmagic from file(1) (optional, for mime-type detection)
libsynctex from TeXLive (optional, for SyncTeX support)
libseccomp (optional, for sandbox support)
Sphinx (optional, for manpages and HTML documentation)
doxygen (optional, for HTML documentation)
breathe (optional, for HTML documentation)
@ -33,6 +34,9 @@ WITH_SQLITE=0 and sqlite support won't be available.
The use of magic to detect mime types is optional and can be disabled by setting
WITH_MAGIC=0.
The use of seccomp to create a sandboxed environment is optional and can be disabled by setting
WITH_SECCOMP=0.
If you pass these flags as a command line argument to make, you have to ensure
to pass the same flags when executing the install target.

View file

@ -47,9 +47,9 @@ WITH_SYNCTEX ?= $(shell (${PKG_CONFIG} synctex && echo 1) || echo 0)
# To disable support for mimetype detction with libmagic set WITH_MAGIC to 0.
WITH_MAGIC ?= 1
# seccomp
# To enable support for seccomp filter set WITH_SECCOMP to 1.
WITH_SECCOMP ?= 0
# seccomp sandbox
# To disable support for seccomp filter set WITH_SECCOMP to 0.
WITH_SECCOMP ?= 1
# paths
PREFIX ?= /usr

View file

@ -185,6 +185,8 @@ config_load_default(zathura_t* zathura)
girara_setting_add(gsession, "index-active-fg", "#232323", STRING, true, _("Index mode foreground color (active element)"), NULL, NULL);
girara_setting_add(gsession, "index-active-bg", "#9FBC00", STRING, true, _("Index mode background color (active element)"), NULL, NULL);
girara_setting_add(gsession, "sandbox", "normal", STRING, true, _("Sandbox level"), NULL, NULL);
bool_value = false;
girara_setting_add(gsession, "recolor", &bool_value, BOOLEAN, false, _("Recolor pages"), cb_setting_recolor_change, NULL);
bool_value = false;

View file

@ -13,7 +13,7 @@
#define DENY_RULE(call) { if (seccomp_rule_add (ctx, SCMP_ACT_KILL, SCMP_SYS(call), 0) < 0) goto out; }
#define ALLOW_RULE(call) { if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(call), 0) < 0) goto out; }
int seccomp_enable_protected_mode(void){
int seccomp_enable_basic_filter(void){
scmp_filter_ctx ctx;
@ -87,274 +87,10 @@ int seccomp_enable_protected_mode(void){
DENY_RULE (umount2);
DENY_RULE (uselib);
DENY_RULE (vmsplice);
/* applying filter... */
if (seccomp_load (ctx) >= 0){
/* free ctx after the filter has been loaded into the kernel */
seccomp_release(ctx);
return 0;
}
out:
/* something went wrong */
seccomp_release(ctx);
return 1;
}
int seccomp_enable_protected_view(void){
scmp_filter_ctx ctx;
/* prevent child processes from getting more priv e.g. via setuid, capabilities, ... */
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
perror("prctl SET_NO_NEW_PRIVS");
exit(EXIT_FAILURE);
}
/* prevent escape via ptrace */
if(prctl (PR_SET_DUMPABLE, 0, 0, 0, 0)){
perror("prctl PR_SET_DUMPABLE");
exit(EXIT_FAILURE);
}
/* initialize the filter */
ctx = seccomp_init(SCMP_ACT_KILL);
if (ctx == NULL){
perror("seccomp_init failed");
exit(EXIT_FAILURE);
}
ALLOW_RULE (access);
ALLOW_RULE (bind);
ALLOW_RULE (brk);
ALLOW_RULE (clock_getres);
ALLOW_RULE (clone);
ALLOW_RULE (close);
ALLOW_RULE (connect);
ALLOW_RULE (eventfd2);
ALLOW_RULE (exit);
ALLOW_RULE (exit_group);
ALLOW_RULE (fadvise64);
ALLOW_RULE (fallocate);
ALLOW_RULE (fcntl); /* TODO: build detailed filter */
ALLOW_RULE (fstat);
ALLOW_RULE (fstatfs);
ALLOW_RULE (ftruncate);
ALLOW_RULE (futex);
ALLOW_RULE (getdents);
ALLOW_RULE (getegid);
ALLOW_RULE (geteuid);
ALLOW_RULE (getgid);
ALLOW_RULE (getuid);
ALLOW_RULE (getpid);
ALLOW_RULE (getppid);
ALLOW_RULE (getpgrp);
ALLOW_RULE (getpeername);
ALLOW_RULE (getrandom);
ALLOW_RULE (getresgid);
ALLOW_RULE (getresuid);
ALLOW_RULE (getrlimit);
ALLOW_RULE (getsockname);
ALLOW_RULE (getsockopt); /* needed for access to x11 socket in network namespace (without abstract sockets) */
ALLOW_RULE (inotify_add_watch);
ALLOW_RULE (inotify_init1);
ALLOW_RULE (inotify_rm_watch);
/* ALLOW_RULE (ioctl); specified below */
ALLOW_RULE (lseek);
ALLOW_RULE (lstat);
ALLOW_RULE (madvise);
ALLOW_RULE (memfd_create);
ALLOW_RULE (mkdir); /* needed for first run only */
ALLOW_RULE (mmap);
ALLOW_RULE (mprotect);
ALLOW_RULE (mremap);
ALLOW_RULE (munmap);
ALLOW_RULE (open); /* (zathura needs to open for writing) TODO: avoid needing this somehow */
ALLOW_RULE (openat);
ALLOW_RULE (pipe);
ALLOW_RULE (poll);
ALLOW_RULE (pwrite64); /* TODO: build detailed filter */
ALLOW_RULE (pread64);
ALLOW_RULE (prlimit64);
ALLOW_RULE (prctl); /* NOT specified below */
ALLOW_RULE (read);
ALLOW_RULE (readlink);
ALLOW_RULE (recvfrom);
ALLOW_RULE (recvmsg);
ALLOW_RULE (restart_syscall);
ALLOW_RULE (rt_sigaction);
ALLOW_RULE (rt_sigprocmask);
ALLOW_RULE (seccomp);
ALLOW_RULE (sendmsg);
ALLOW_RULE (sendto);
ALLOW_RULE (select);
ALLOW_RULE (set_robust_list);
ALLOW_RULE (setsockopt);
ALLOW_RULE (shmat);
ALLOW_RULE (shmctl);
ALLOW_RULE (shmdt);
ALLOW_RULE (shmget);
ALLOW_RULE (shutdown);
ALLOW_RULE (stat);
ALLOW_RULE (statfs);
/* ALLOW_RULE (socket); specified below */
ALLOW_RULE (sysinfo);
ALLOW_RULE (uname);
ALLOW_RULE (unlink);
ALLOW_RULE (write); /* specified below (zathura needs to write files)*/
ALLOW_RULE (writev);
ALLOW_RULE (wait4); /* trying to open links should not crash the app */
/* allowed for use with container */
ALLOW_RULE (chmod);
ALLOW_RULE (link);
ALLOW_RULE (rename);
/* allowed for debugging: */
/* ALLOW_RULE (prctl); */
/* ALLOW_RULE (ioctl); */
/* incomplete */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, F_GETFL)) < 0) */
/* goto out; */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, F_SETFL)) < 0) */
/* goto out; */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, F_SETFD)) < 0) */
/* goto out; */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, F_GETFD)) < 0) */
/* goto out; */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, F_SETLK)) < 0) */
/* goto out; */
/* Special requirements for ioctl, allowed on stdout/stderr */
if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
SCMP_CMP(0, SCMP_CMP_EQ, 1)) < 0)
goto out;
if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
SCMP_CMP(0, SCMP_CMP_EQ, 2)) < 0)
goto out;
/* TODO: build detailed filter for prctl */
/* needed by gtk??? (does not load content without) */
/* /\* special restrictions for prctl, only allow PR_SET_NAME/PR_SET_PDEATHSIG *\/ */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_NAME)) < 0) */
/* goto out; */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_PDEATHSIG)) < 0) */
/* goto out; */
/* when zathura is run on wayland, with X11 server available but blocked, unset the DISPLAY variable */
/* otherwise it will try to connect to X11 using inet socket protocol */
/* required changes in links.c (at girara_xdg_open) */
/* special restrictions for socket, only allow AF_UNIX/AF_LOCAL */
if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
SCMP_CMP(0, SCMP_CMP_EQ, AF_UNIX)) < 0)
goto out;
if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
SCMP_CMP(0, SCMP_CMP_EQ, AF_LOCAL)) < 0)
goto out;
/* TODO: avoid the need for the open syscall to be allowed with write permissions */
/* zathura needs to open files for writing to save current position */
/* /\* special restrictions for open, prevent opening files for writing *\/ */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 1, */
/* SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR, 0)) < 0) */
/* goto out; */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ERRNO (EACCES), SCMP_SYS(open), 1, */
/* SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY)) < 0) */
/* goto out; */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ERRNO (EACCES), SCMP_SYS(open), 1, */
/* SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR)) < 0) */
/* goto out; */
/* ------------ experimental filters --------------- */
/* /\* this filter is susceptible to TOCTOU race conditions, providing limited use *\/ */
/* /\* allow opening only specified files identified by their file descriptors*\/ */
/* this requires either a list of all files to open (A LOT!!!) */
/* or needs to be applied only after initialisation, right before parsing */
/* if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1, */
/* SCMP_CMP(SCMP_CMP_EQ, fd)) < 0) /\* or < 1 ??? *\/ */
/* goto out; */
/* /\* restricting write access *\/ */
/* /\* allow stdin *\/ */
/* if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, 0)) < 0 ) */
/* goto out; */
/* /\* allow stdout *\/ */
/* if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, 1)) < 0 ) */
/* goto out; */
/* /\* allow stderr *\/ */
/* if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, 2)) < 0 ) */
/* goto out; */
/* /\* restrict writev (write a vector) access *\/ */
/* this does not seem reliable but it surprisingly is. investigate more */
/* if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(writev), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, 3)) < 0 ) */
/* goto out; */
/* test if repeating this after some time or denying it works */
/* first attempt to filter poll requests */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(poll), 1, */
/* SCMP_CMP(0, SCMP_CMP_MASKED_EQ, POLLIN | POLL, 0)) < 0) */
/* goto out; */
/* /\* restrict fcntl calls *\/ */
/* this syscall sets the file descriptor to read write */
/* if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, 3)) < 0 ) */
/* goto out; */
/* fcntl(3, F_GETFL) = 0x2 (flags O_RDWR) */
/* fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 */
/* fcntl(3, F_SETFD, FD_CLOEXEC) = 0 */
/* ------------------ end of experimental filters ------------------ */
/* TODO: check for additional syscalls to blacklist */
/* DENY_RULE (execve); */
/* applying filter... */
if (seccomp_load (ctx) >= 0){
/* free ctx after the filter has been loaded into the kernel */
@ -526,6 +262,104 @@ int seccomp_enable_strict_filter(void){
/* ALLOW_RULE (ioctl); */
/* TODO: test fcntl rules */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, F_GETFL)) < 0) */
/* goto out; */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, F_SETFL)) < 0) */
/* goto out; */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, F_SETFD)) < 0) */
/* goto out; */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, F_GETFD)) < 0) */
/* goto out; */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, F_SETLK)) < 0) */
/* goto out; */
/* TODO: build detailed filter for prctl */
/* needed by gtk??? (does not load content without) */
/* /\* special restrictions for prctl, only allow PR_SET_NAME/PR_SET_PDEATHSIG *\/ */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_NAME)) < 0) */
/* goto out; */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_PDEATHSIG)) < 0) */
/* goto out; */
/* when zathura is run on wayland, with X11 server available but blocked, unset the DISPLAY variable */
/* otherwise it will try to connect to X11 using inet socket protocol */
/* ------------ experimental filters --------------- */
/* /\* this filter is susceptible to TOCTOU race conditions, providing limited use *\/ */
/* /\* allow opening only specified files identified by their file descriptors*\/ */
/* this requires either a list of all files to open (A LOT!!!) */
/* or needs to be applied only after initialisation, right before parsing */
/* if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1, */
/* SCMP_CMP(SCMP_CMP_EQ, fd)) < 0) /\* or < 1 ??? *\/ */
/* goto out; */
/* /\* restricting write access *\/ */
/* /\* allow stdin *\/ */
/* if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, 0)) < 0 ) */
/* goto out; */
/* /\* allow stdout *\/ */
/* if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, 1)) < 0 ) */
/* goto out; */
/* /\* allow stderr *\/ */
/* if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, 2)) < 0 ) */
/* goto out; */
/* /\* restrict writev (write a vector) access *\/ */
/* this does not seem reliable but it surprisingly is. investigate more */
/* if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(writev), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, 3)) < 0 ) */
/* goto out; */
/* test if repeating this after some time or denying it works */
/* first attempt to filter poll requests */
/* if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(poll), 1, */
/* SCMP_CMP(0, SCMP_CMP_MASKED_EQ, POLLIN | POLL, 0)) < 0) */
/* goto out; */
/* /\* restrict fcntl calls *\/ */
/* this syscall sets the file descriptor to read write */
/* if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1, */
/* SCMP_CMP(0, SCMP_CMP_EQ, 3)) < 0 ) */
/* goto out; */
/* fcntl(3, F_GETFL) = 0x2 (flags O_RDWR) */
/* fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 */
/* fcntl(3, F_SETFD, FD_CLOEXEC) = 0 */
/* ------------------ end of experimental filters ------------------ */
/* applying filter... */
if (seccomp_load (ctx) >= 0){
/* free ctx after the filter has been loaded into the kernel */

View file

@ -4,13 +4,7 @@
/* basic filter */
/* this mode allows normal use */
/* only dangerous syscalls are blacklisted */
int seccomp_enable_protected_mode(void);
/* secure whitelist filter */
/* whitelist minimal syscalls only */
/* this mode does not allow to open external links or to start applications */
/* network connections are prohibited as well */
int seccomp_enable_protected_view(void);
int seccomp_enable_basic_filter(void);
/* strict filter before document parsing */
/* this filter is to be enabled after most of the initialisation of zathura has finished */

View file

@ -135,6 +135,10 @@ zathura_link_evaluate(zathura_t* zathura, zathura_link_t* link)
bool link_zoom = true;
girara_setting_get(zathura->ui.session, "link-zoom", &link_zoom);
/* required below to prevent opening hyperlinks in strict sandbox mode */
char* sandbox = NULL;
girara_setting_get(zathura->ui.session, "sandbox", &sandbox);
switch (link->type) {
case ZATHURA_LINK_GOTO_DEST:
if (link->target.destination_type != ZATHURA_LINK_DESTINATION_UNKNOWN) {
@ -203,13 +207,13 @@ zathura_link_evaluate(zathura_t* zathura, zathura_link_t* link)
link_remote(zathura, link->target.value);
break;
case ZATHURA_LINK_URI:
#ifndef WITH_SECCOMP
if (girara_xdg_open(link->target.value) == false) {
girara_notify(zathura->ui.session, GIRARA_ERROR, _("Failed to run xdg-open."));
if (g_strcmp0(sandbox, "strict") == 0) {
girara_notify(zathura->ui.session, GIRARA_ERROR, _("Opening external applications in strict sandbox mode is not permitted"));
} else {
if (girara_xdg_open(link->target.value) == false) {
girara_notify(zathura->ui.session, GIRARA_ERROR, _("Failed to run xdg-open."));
}
}
#else
girara_notify(zathura->ui.session, GIRARA_ERROR, _("Opening external apps in protectedView Sandbox mode is not permitted"));
#endif
break;
case ZATHURA_LINK_LAUNCH:
link_launch(zathura, link);

View file

@ -127,10 +127,6 @@ int
main(int argc, char* argv[])
{
#ifdef WITH_SECCOMP
seccomp_enable_protected_view();
#endif
init_locale();
/* parse command line arguments */
@ -298,8 +294,20 @@ main(int argc, char* argv[])
}
#ifdef WITH_SECCOMP
/* enforce strict syscall filter before parsing the document */
seccomp_enable_strict_filter();
char* sandbox = NULL;
girara_setting_get(zathura->ui.session, "sandbox", &sandbox);
if (g_strcmp0(sandbox, "none") == 0) {
girara_debug("Sandbox deactivated.");
} else if (g_strcmp0(sandbox, "normal") == 0) {
girara_debug("Basic sandbox allowing normal operation.");
seccomp_enable_basic_filter();
} else if (g_strcmp0(sandbox, "strict") == 0) {
girara_debug("Strict sandbox preventing write and network access.");
seccomp_enable_strict_filter();
}
#endif
/* open document if passed */