From 1ad2d54c014a49f6ad0b487dd0d9b361cb4d299e Mon Sep 17 00:00:00 2001 From: Topi Miettinen Date: Tue, 18 Feb 2020 20:38:00 +0200 Subject: Add support for SELinux labeling Running `firejail --noprofile --private-bin=bash,ls ls -1Za /usr/bin` shows that the SELinux labels are not correct: ``` user_u:object_r:user_tmpfs_t:s0 . system_u:object_r:usr_t:s0 .. user_u:object_r:user_tmpfs_t:s0 bash user_u:object_r:user_tmpfs_t:s0 ls ``` After fixing this: ``` system_u:object_r:bin_t:s0 . system_u:object_r:usr_t:s0 .. system_u:object_r:shell_exec_t:s0 bash system_u:object_r:bin_t:s0 ls ``` Most copied files and created directories should now have correct labels (bind mounted objects keep their labels). This is useful to avoid having to change the SELinux rules when using Firejail. --- README | 2 +- README.md | 2 +- configure | 18 +++++++++++ configure.ac | 10 ++++++ src/common.mk.in | 3 +- src/fcopy/main.c | 57 +++++++++++++++++++++++++++++++++ src/firejail/firejail.h | 3 ++ src/firejail/fs_bin.c | 1 + src/firejail/fs_dev.c | 4 +++ src/firejail/fs_etc.c | 2 ++ src/firejail/fs_home.c | 14 +++++++++ src/firejail/fs_hostname.c | 1 + src/firejail/fs_lib.c | 1 + src/firejail/fs_lib2.c | 1 + src/firejail/fs_var.c | 2 ++ src/firejail/fs_whitelist.c | 13 ++++++++ src/firejail/pulseaudio.c | 1 + src/firejail/restrict_users.c | 4 +++ src/firejail/sandbox.c | 29 ++++++++--------- src/firejail/selinux.c | 73 +++++++++++++++++++++++++++++++++++++++++++ 20 files changed, 224 insertions(+), 17 deletions(-) create mode 100644 src/firejail/selinux.c diff --git a/README b/README index d33fa3e81..61d94bec9 100644 --- a/README +++ b/README @@ -29,7 +29,7 @@ development libraries and pkg-config are required when using --apparmor $ sudo apt-get install git build-essential libapparmor-dev pkg-config - +For --selinux option, add libselinux1-dev (libselinux-devel for Fedora). Maintainer: - netblue30 (netblue30@yahoo.com) diff --git a/README.md b/README.md index 4391ac331..dce1f9cfb 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ development libraries and pkg-config are required when using --apparmor ````` $ sudo apt-get install git build-essential libapparmor-dev pkg-config ````` - +For --selinux option, add libselinux1-dev (libselinux-devel for Fedora). ## Running the sandbox diff --git a/configure b/configure index 94f719710..53ea8f19d 100755 --- a/configure +++ b/configure @@ -628,6 +628,7 @@ HAVE_SECCOMP_H EGREP GREP CPP +HAVE_SELINUX HAVE_CONTRIB_INSTALL HAVE_GCOV BUSYBOX_WORKAROUND @@ -721,6 +722,7 @@ enable_fatal_warnings enable_busybox_workaround enable_gcov enable_contrib_install +enable_selinux ' ac_precious_vars='build_alias host_alias @@ -1365,6 +1367,7 @@ Optional Features: --enable-gcov Gcov instrumentation --enable-contrib-install install contrib scripts + --enable-selinux SELinux labeling support Some influential environment variables: CC C compiler command @@ -3695,6 +3698,20 @@ else fi +HAVE_SELINUX="" +# Check whether --enable-selinux was given. +if test "${enable_selinux+set}" = set; then : + enableval=$enable_selinux; +fi + +if test "x$enable_selinux" = "xyes"; then : + + HAVE_SELINUX="-DHAVE_SELINUX" + EXTRA_LDFLAGS+=" -lselinux " + + +fi + # checking pthread library { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lpthread" >&5 $as_echo_n "checking for main in -lpthread... " >&6; } @@ -5364,5 +5381,6 @@ echo " EXTRA_CFLAGS: $EXTRA_CFLAGS" echo " fatal warnings: $HAVE_FATAL_WARNINGS" echo " Gcov instrumentation: $HAVE_GCOV" echo " Install contrib scripts: $HAVE_CONTRIB_INSTALL" +echo " SELinux labeling support: $HAVE_SELINUX" echo " Install as a SUID executable: $HAVE_SUID" echo diff --git a/configure.ac b/configure.ac index 8ee2fbadc..3c9f901cb 100644 --- a/configure.ac +++ b/configure.ac @@ -184,6 +184,15 @@ AS_IF([test "x$enable_contrib_install" = "xno"], ) AC_SUBST(HAVE_CONTRIB_INSTALL) +HAVE_SELINUX="" +AC_ARG_ENABLE([selinux], + AS_HELP_STRING([--enable-selinux], [SELinux labeling support])) +AS_IF([test "x$enable_selinux" = "xyes"], [ + HAVE_SELINUX="-DHAVE_SELINUX" + EXTRA_LDFLAGS+=" -lselinux " + AC_SUBST(HAVE_SELINUX) +]) + # checking pthread library AC_CHECK_LIB([pthread], [main], [], AC_MSG_ERROR([*** POSIX thread support not installed ***])) AC_CHECK_HEADER(pthread.h,,AC_MSG_ERROR([*** POSIX thread support not installed ***])) @@ -223,5 +232,6 @@ echo " EXTRA_CFLAGS: $EXTRA_CFLAGS" echo " fatal warnings: $HAVE_FATAL_WARNINGS" echo " Gcov instrumentation: $HAVE_GCOV" echo " Install contrib scripts: $HAVE_CONTRIB_INSTALL" +echo " SELinux labeling support: $HAVE_SELINUX" echo " Install as a SUID executable: $HAVE_SUID" echo diff --git a/src/common.mk.in b/src/common.mk.in index 1464ab9b2..945815a40 100644 --- a/src/common.mk.in +++ b/src/common.mk.in @@ -24,6 +24,7 @@ HAVE_OVERLAYFS=@HAVE_OVERLAYFS@ HAVE_FIRETUNNEL=@HAVE_FIRETUNNEL@ HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ HAVE_GCOV=@HAVE_GCOV@ +HAVE_SELINUX=@HAVE_SELINUX@ H_FILE_LIST = $(sort $(wildcard *.[h])) C_FILE_LIST = $(sort $(wildcard *.c)) @@ -32,7 +33,7 @@ BINOBJS = $(foreach file, $(OBJS), $file) CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' $(HAVE_GCOV) CFLAGS += -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' -DBINDIR='"$(bindir)"' -CFLAGS += $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_FIRETUNNEL) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) +CFLAGS += $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_FIRETUNNEL) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) $(HAVE_SELINUX) CFLAGS += -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ diff --git a/src/fcopy/main.c b/src/fcopy/main.c index 5c4a76753..83d9c17e6 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c @@ -24,6 +24,15 @@ #include #include +#if HAVE_SELINUX +#include +#include + +#include +#include +#include +#endif + int arg_quiet = 0; int arg_debug = 0; static int arg_follow_link = 0; @@ -36,6 +45,52 @@ static unsigned file_cnt = 0; static char *outpath = NULL; static char *inpath = NULL; +#if HAVE_SELINUX +static struct selabel_handle *label_hnd = NULL; +static int selinux_enabled = -1; +#endif + +// copy from firejail/selinux.c +static void selinux_relabel_path(const char *path, const char *inside_path) +{ +#if HAVE_SELINUX + char procfs_path[64]; + char *fcon = NULL; + int fd; + struct stat st; + + if (selinux_enabled == -1) + selinux_enabled = is_selinux_enabled(); + + if (!selinux_enabled) + return; + + if (!label_hnd) + label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); + + /* Open the file as O_PATH, to pin it while we determine and adjust the label */ + fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); + if (fd < 0) + return; + if (fstat(fd, &st) < 0) + goto close; + + if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) == 0) { + sprintf(procfs_path, "/proc/self/fd/%i", fd); + if (arg_debug) + printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon); + + setfilecon_raw(procfs_path, fcon); + } + freecon(fcon); + close: + close(fd); +#else + (void) path; + (void) inside_path; +#endif +} + // modified version of the function from util.c static void copy_file(const char *srcname, const char *destname, mode_t mode, uid_t uid, gid_t gid) { assert(srcname); @@ -87,6 +142,8 @@ static void copy_file(const char *srcname, const char *destname, mode_t mode, ui close(src); close(dst); + selinux_relabel_path(destname, srcname); + return; errexit: diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 4dc580a5e..66328a55e 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -833,4 +833,7 @@ extern pid_t dhclient4_pid; extern pid_t dhclient6_pid; void dhcp_start(void); +// selinux.c +void selinux_relabel_path(const char *path, const char *inside_path); + #endif diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c index 7150fd3eb..a48d6cf67 100644 --- a/src/firejail/fs_bin.c +++ b/src/firejail/fs_bin.c @@ -309,5 +309,6 @@ void fs_private_bin_list(void) { } i++; } + selinux_relabel_path(RUN_BIN_DIR, "/bin"); fmessage("%d %s installed in %0.2f ms\n", prog_cnt, (prog_cnt == 1)? "program": "programs", timetrace_end()); } diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c index 63911ab9e..500b6bf1b 100644 --- a/src/firejail/fs_dev.c +++ b/src/firejail/fs_dev.c @@ -167,6 +167,7 @@ static void create_link(const char *oldpath, const char *newpath) { static void empty_dev_shm(void) { // create an empty /dev/shm directory mkdir_attr("/dev/shm", 01777, 0, 0); + selinux_relabel_path("/dev/shm", "/dev/shm"); fs_logger("mkdir /dev/shm"); fs_logger("create /dev/shm"); } @@ -276,10 +277,13 @@ void fs_private_dev(void){ // pseudo-terminal mkdir_attr("/dev/pts", 0755, 0, 0); fs_logger("mkdir /dev/pts"); + selinux_relabel_path("/dev/pts", "/dev/pts"); fs_logger("create /dev/pts"); create_char_dev("/dev/pts/ptmx", 0666, 5, 2); //"mknod -m 666 /dev/pts/ptmx c 5 2"); + selinux_relabel_path("/dev/pts/ptmx", "/dev/pts/ptmx"); fs_logger("mknod /dev/pts/ptmx"); create_link("/dev/pts/ptmx", "/dev/ptmx"); + selinux_relabel_path("/dev/ptmx", "/dev/ptmx"); // code before github issue #351 // mount -vt devpts -o newinstance -o ptmxmode=0666 devpts //dev/pts diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c index 76bcb751e..271e46855 100644 --- a/src/firejail/fs_etc.c +++ b/src/firejail/fs_etc.c @@ -59,6 +59,7 @@ void fs_machineid(void) { if (set_perms(RUN_MACHINEID, 0, 0, 0444)) errExit("set_perms"); + selinux_relabel_path(RUN_MACHINEID, "/etc/machine-id"); struct stat s; if (stat("/etc/machine-id", &s) == 0) { @@ -154,6 +155,7 @@ void fs_private_dir_list(const char *private_dir, const char *private_run_dir, c // create /run/firejail/mnt/etc directory mkdir_attr(private_run_dir, 0755, 0, 0); + selinux_relabel_path(private_run_dir, private_dir); fs_logger2("tmpfs", private_dir); fs_logger_print(); // save the current log diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index bdfaba480..bec22e5a6 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c @@ -60,6 +60,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { touch_file_as_user(fname, 0644); fs_logger2("touch", fname); } + selinux_relabel_path(fname, fname); free(fname); } // csh @@ -85,6 +86,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { touch_file_as_user(fname, 0644); fs_logger2("touch", fname); } + selinux_relabel_path(fname, fname); free(fname); } // bash etc. @@ -105,6 +107,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { fs_logger("clone /etc/skel/.bashrc"); fs_logger2("clone", fname); } + selinux_relabel_path(fname, fname); free(fname); } } @@ -139,6 +142,7 @@ static int store_xauthority(void) { copy_file_as_user(src, dest, getuid(), getgid(), 0600); // regular user fs_logger2("clone", dest); + selinux_relabel_path(dest, src); free(src); return 1; // file copied } @@ -185,6 +189,7 @@ static int store_asoundrc(void) { errExit("fopen"); copy_file_as_user(src, dest, getuid(), getgid(), 0644); // regular user + selinux_relabel_path(dest, src); fs_logger2("clone", dest); free(src); return 1; // file copied @@ -208,6 +213,7 @@ static void copy_xauthority(void) { } copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user + selinux_relabel_path(dest, src); fs_logger2("clone", dest); free(dest); @@ -313,6 +319,7 @@ void fs_private_homedir(void) { printf("Mounting a new /root directory\n"); if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_STRICTATIME, "mode=700,gid=0") < 0) errExit("mounting /root directory"); + selinux_relabel_path("/root", "/root"); fs_logger("tmpfs /root"); } if (u == 0 && !arg_allusers) { @@ -321,6 +328,7 @@ void fs_private_homedir(void) { printf("Mounting a new /home directory\n"); if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mounting /home directory"); + selinux_relabel_path("/home", "/home"); fs_logger("tmpfs /home"); } @@ -355,6 +363,7 @@ void fs_private(void) { fwarning("allusers option disabled by private or whitelist option\n"); if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mounting /home directory"); + selinux_relabel_path("/home", "/home"); fs_logger("tmpfs /home"); } @@ -378,6 +387,8 @@ void fs_private(void) { } if (chown(homedir, u, g) < 0) errExit("chown"); + selinux_relabel_path(homedir, homedir); + fs_logger2("mkdir", homedir); fs_logger2("tmpfs", homedir); } @@ -542,6 +553,7 @@ void fs_private_home_list(void) { // create /run/firejail/mnt/home directory mkdir_attr(RUN_HOME_DIR, 0755, uid, gid); + selinux_relabel_path(RUN_HOME_DIR, "/home"); fs_logger_print(); // save the current log if (arg_debug) @@ -604,6 +616,7 @@ void fs_private_home_list(void) { printf("Mounting a new /root directory\n"); if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=700,gid=0") < 0) errExit("mounting /root directory"); + selinux_relabel_path("/root", "/root"); fs_logger("tmpfs /root"); } if (uid == 0 && !arg_allusers) { @@ -612,6 +625,7 @@ void fs_private_home_list(void) { printf("Mounting a new /home directory\n"); if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mounting /home directory"); + selinux_relabel_path("/home", "/home"); fs_logger("tmpfs /home"); } diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c index fd5e1bbd3..5d6fddf8e 100644 --- a/src/firejail/fs_hostname.c +++ b/src/firejail/fs_hostname.c @@ -96,6 +96,7 @@ void fs_resolvconf(void) { printf("mirroring /etc directory\n"); if (mkdir(RUN_DNS_ETC, 0755)) errExit("mkdir"); + selinux_relabel_path(RUN_DNS_ETC, "/etc"); fs_logger("tmpfs /etc"); DIR *dir = opendir("/etc"); diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c index c539ce83c..64444bba2 100644 --- a/src/firejail/fs_lib.c +++ b/src/firejail/fs_lib.c @@ -326,6 +326,7 @@ void fs_private_lib(void) { // create /run/firejail/mnt/lib directory mkdir_attr(RUN_LIB_DIR, 0755, 0, 0); + selinux_relabel_path(RUN_LIB_DIR, "/usr/lib"); // install standard C libraries if (arg_debug || arg_debug_private_lib) diff --git a/src/firejail/fs_lib2.c b/src/firejail/fs_lib2.c index 2982c4cbb..b2ae07f3e 100644 --- a/src/firejail/fs_lib2.c +++ b/src/firejail/fs_lib2.c @@ -109,6 +109,7 @@ void fslib_install_stdc(void) { if (stat("/lib/x86_64-linux-gnu", &s) == 0) { // Debian & friends mkdir_attr(RUN_LIB_DIR "/x86_64-linux-gnu", 0755, 0, 0); + selinux_relabel_path(RUN_LIB_DIR "/x86_64-linux-gnu", "/lib/x86_64-linux-gnu"); stdclib = "/lib/x86_64-linux-gnu"; } diff --git a/src/firejail/fs_var.c b/src/firejail/fs_var.c index 303d6f9aa..cafe9fa49 100644 --- a/src/firejail/fs_var.c +++ b/src/firejail/fs_var.c @@ -223,9 +223,11 @@ void fs_var_cache(void) { } mkdir_attr("/var/cache/lighttpd/compress", 0755, uid, gid); + selinux_relabel_path("/var/cache/lighttpd/compress", "/var/cache/lighttpd/compress"); fs_logger("mkdir /var/cache/lighttpd/compress"); mkdir_attr("/var/cache/lighttpd/uploads", 0755, uid, gid); + selinux_relabel_path("/var/cache/lighttpd/uploads", "/var/cache/lighttpd/uploads"); fs_logger("/var/cache/lighttpd/uploads"); } } diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c index be5bcc4c0..c5b066b12 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c @@ -734,6 +734,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /tmp directory\n"); if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=1777,gid=0") < 0) errExit("mounting tmpfs on /tmp"); + selinux_relabel_path("/tmp", "/tmp"); fs_logger("tmpfs /tmp"); // pam-tmpdir - issue #2685 @@ -745,8 +746,10 @@ void fs_whitelist(void) { if (strcmp(env, pamtmpdir) == 0) { // create empty user-owned /tmp/user/$uid directory mkdir_attr("/tmp/user", 0711, 0, 0); + selinux_relabel_path("/tmp/user", "/tmp/user"); fs_logger("mkdir /tmp/user"); mkdir_attr(pamtmpdir, 0700, getuid(), 0); + selinux_relabel_path(pamtmpdir, pamtmpdir); fs_logger2("mkdir", pamtmpdir); } free(pamtmpdir); @@ -774,6 +777,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /media directory\n"); if (mount("tmpfs", "/media", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /media"); + selinux_relabel_path("/media", "/media"); fs_logger("tmpfs /media"); // autowhitelist home directory if it is masked by the tmpfs @@ -798,6 +802,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /mnt directory\n"); if (mount("tmpfs", "/mnt", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /mnt"); + selinux_relabel_path("/mnt", "/mnt"); fs_logger("tmpfs /mnt"); // autowhitelist home directory if it is masked by the tmpfs @@ -822,6 +827,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /var directory\n"); if (mount("tmpfs", "/var", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /var"); + selinux_relabel_path("/var", "/var"); fs_logger("tmpfs /var"); // autowhitelist home directory if it is masked by the tmpfs @@ -846,6 +852,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /dev directory\n"); if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /dev"); + selinux_relabel_path("/dev", "/dev"); fs_logger("tmpfs /dev"); // autowhitelist home directory if it is masked by the tmpfs @@ -870,6 +877,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /opt directory\n"); if (mount("tmpfs", "/opt", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /opt"); + selinux_relabel_path("/opt", "/opt"); fs_logger("tmpfs /opt"); // autowhitelist home directory if it is masked by the tmpfs @@ -894,6 +902,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /srv directory\n"); if (mount("tmpfs", "/srv", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /srv"); + selinux_relabel_path("/srv", "/srv"); fs_logger("tmpfs /srv"); // autowhitelist home directory if it is masked by the tmpfs @@ -918,6 +927,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /etc directory\n"); if (mount("tmpfs", "/etc", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /etc"); + selinux_relabel_path("/etc", "/etc"); fs_logger("tmpfs /etc"); // autowhitelist home directory if it is masked by the tmpfs @@ -942,6 +952,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /usr/share directory\n"); if (mount("tmpfs", "/usr/share", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /usr/share"); + selinux_relabel_path("/usr/share", "/usr/share"); fs_logger("tmpfs /usr/share"); // autowhitelist home directory if it is masked by the tmpfs @@ -966,6 +977,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /sys/module directory\n"); if (mount("tmpfs", "/sys/module", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /sys/module"); + selinux_relabel_path("/sys/module", "/sys/module"); fs_logger("tmpfs /sys/module"); } else @@ -989,6 +1001,7 @@ void fs_whitelist(void) { errExit("asprintf"); if (mount("tmpfs", runuser, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, options) < 0) errExit("mounting tmpfs on /run/user/"); + selinux_relabel_path(runuser, runuser); free(options); fs_logger2("tmpfs", runuser); diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c index 57095a53c..a8fb838ab 100644 --- a/src/firejail/pulseaudio.c +++ b/src/firejail/pulseaudio.c @@ -87,6 +87,7 @@ void pulseaudio_init(void) { // create the new user pulseaudio directory if (mkdir(RUN_PULSE_DIR, 0700) == -1) errExit("mkdir"); + selinux_relabel_path(RUN_PULSE_DIR, RUN_PULSE_DIR); // mount it nosuid, noexec, nodev fs_remount(RUN_PULSE_DIR, MOUNT_NOEXEC, 0); diff --git a/src/firejail/restrict_users.c b/src/firejail/restrict_users.c index b51172219..5ebb0e9ec 100644 --- a/src/firejail/restrict_users.c +++ b/src/firejail/restrict_users.c @@ -97,6 +97,7 @@ static void sanitize_home(void) { // mount tmpfs in the new home if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mount tmpfs"); + selinux_relabel_path("/home", "/home"); fs_logger("tmpfs /home"); // create user home directory @@ -105,6 +106,7 @@ static void sanitize_home(void) { errExit("mkpath"); if (mkdir(cfg.homedir, 0755) == -1) errExit("mkdir"); + selinux_relabel_path(cfg.homedir, cfg.homedir); } fs_logger2("mkdir", cfg.homedir); @@ -152,11 +154,13 @@ static void sanitize_run(void) { // mount tmpfs on /run/user if (mount("tmpfs", "/run/user", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) errExit("mount tmpfs"); + selinux_relabel_path("/run/user", "/run/user"); fs_logger("tmpfs /run/user"); // create new user directory if (mkdir(runuser, 0700) == -1) errExit("mkdir"); + selinux_relabel_path(runuser, runuser); fs_logger2("mkdir", runuser); // set mode and ownership diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 4f53cafcc..d1d98f636 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c @@ -848,20 +848,6 @@ int sandbox(void* sandbox_arg) { if (arg_private_dev) fs_private_dev(); - if (arg_private_etc) { - if (cfg.chrootdir) - fwarning("private-etc feature is disabled in chroot\n"); - else if (arg_overlay) - fwarning("private-etc feature is disabled in overlay\n"); - else { - fs_private_dir_list("/etc", RUN_ETC_DIR, cfg.etc_private_keep); - fs_private_dir_list("/usr/etc", RUN_USR_ETC_DIR, cfg.etc_private_keep); // openSUSE - // create /etc/ld.so.preload file again - if (need_preload) - fs_trace_preload(); - } - } - if (arg_private_opt) { if (cfg.chrootdir) fwarning("private-opt feature is disabled in chroot\n"); @@ -964,6 +950,21 @@ int sandbox(void* sandbox_arg) { else if (arg_disable_mnt) fs_mnt(0); + // Install new /etc last, so we can use it as long as possible + if (arg_private_etc) { + if (cfg.chrootdir) + fwarning("private-etc feature is disabled in chroot\n"); + else if (arg_overlay) + fwarning("private-etc feature is disabled in overlay\n"); + else { + fs_private_dir_list("/etc", RUN_ETC_DIR, cfg.etc_private_keep); + fs_private_dir_list("/usr/etc", RUN_USR_ETC_DIR, cfg.etc_private_keep); // openSUSE + // create /etc/ld.so.preload file again + if (need_preload) + fs_trace_preload(); + } + } + //**************************** // apply the profile file //**************************** diff --git a/src/firejail/selinux.c b/src/firejail/selinux.c new file mode 100644 index 000000000..52d6788ef --- /dev/null +++ b/src/firejail/selinux.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2020 Firejail and systemd authors + * + * This file is part of firejail project, from systemd selinux-util.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#if HAVE_SELINUX +#include "firejail.h" + +#include +#include +#include + +#include +#include +#include + +static struct selabel_handle *label_hnd = NULL; +static int selinux_enabled = -1; +#endif + +void selinux_relabel_path(const char *path, const char *inside_path) +{ +#if HAVE_SELINUX + char procfs_path[64]; + char *fcon = NULL; + int fd; + struct stat st; + + if (selinux_enabled == -1) + selinux_enabled = is_selinux_enabled(); + + if (!selinux_enabled && arg_debug) + return; + + if (!label_hnd) + label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); + + /* Open the file as O_PATH, to pin it while we determine and adjust the label */ + fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); + if (fd < 0) + return; + if (fstat(fd, &st) < 0) + goto close; + + if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) == 0) { + sprintf(procfs_path, "/proc/self/fd/%i", fd); + if (arg_debug) + printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon); + + setfilecon_raw(procfs_path, fcon); + } + freecon(fcon); + close: + close(fd); +#else + (void) path; + (void) inside_path; +#endif +} -- cgit v1.2.3-70-g09d2