From 9e18bf8a10a3b9b948c15853ad716cf8e3673fcf Mon Sep 17 00:00:00 2001 From: smitsohu Date: Wed, 29 Sep 2021 15:49:52 +0200 Subject: add more EUID improvements --- src/fcopy/main.c | 3 ++- src/firejail/fs.c | 12 ++++----- src/firejail/fs_dev.c | 2 ++ src/firejail/fs_home.c | 11 ++++++--- src/firejail/fs_whitelist.c | 59 +++++++++++++++++++-------------------------- src/firejail/sandbox.c | 2 ++ src/firejail/selinux.c | 21 +++++++++++++++- src/firejail/util.c | 14 ++--------- 8 files changed, 65 insertions(+), 59 deletions(-) diff --git a/src/fcopy/main.c b/src/fcopy/main.c index 31810de9a..f279af89f 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c @@ -88,7 +88,8 @@ static void selinux_relabel_path(const char *path, const char *inside_path) { if (arg_debug) printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon); - setfilecon_raw(procfs_path, fcon); + if (setfilecon_raw(procfs_path, fcon) != 0 && arg_debug) + printf("Cannot relabel %s: %s\n", path, strerror(errno)); } freecon(fcon); close: diff --git a/src/firejail/fs.c b/src/firejail/fs.c index dd4c2139d..6d01b5e5d 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c @@ -200,8 +200,6 @@ static void disable_file(OPERATION op, const char *filename) { } fs_tmpfs(fname, uid); - EUID_USER(); // fs_tmpfs returns with EUID 0 - selinux_relabel_path(fname, fname); } else @@ -282,6 +280,8 @@ static void globbing(OPERATION op, const char *pattern, const char *noblacklist[ // blacklist files or directories by mounting empty files on top of them void fs_blacklist(void) { + EUID_ASSERT(); + ProfileEntry *entry = cfg.profile; if (!entry) return; @@ -293,7 +293,6 @@ void fs_blacklist(void) { if (noblacklist == NULL) errExit("failed allocating memory for noblacklist entries"); - EUID_USER(); while (entry) { OPERATION op = OPERATION_MAX; char *ptr; @@ -469,8 +468,6 @@ void fs_blacklist(void) { for (i = 0; i < noblacklist_c; i++) free(noblacklist[i]); free(noblacklist); - - EUID_ROOT(); } //*********************************************** @@ -479,7 +476,7 @@ void fs_blacklist(void) { // mount a writable tmpfs on directory; requires a resolved path void fs_tmpfs(const char *dir, unsigned check_owner) { - EUID_USER(); + EUID_ASSERT(); assert(dir); if (arg_debug) printf("Mounting tmpfs on %s, check owner: %s\n", dir, (check_owner)? "yes": "no"); @@ -504,12 +501,13 @@ void fs_tmpfs(const char *dir, unsigned check_owner) { errExit("fstatvfs"); unsigned long flags = buf.f_flag & ~(MS_RDONLY|MS_BIND|MS_REMOUNT); // mount via the symbolic link in /proc/self/fd - EUID_ROOT(); char *proc; if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) errExit("asprintf"); + EUID_ROOT(); if (mount("tmpfs", proc, "tmpfs", flags|MS_NOSUID|MS_NODEV, options) < 0) errExit("mounting tmpfs"); + EUID_USER(); // check the last mount operation MountData *mdata = get_last_mount(); if (strcmp(mdata->fstype, "tmpfs") != 0 || strcmp(mdata->dir, dir) != 0) diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c index 8cc3ecc62..a43b18344 100644 --- a/src/firejail/fs_dev.c +++ b/src/firejail/fs_dev.c @@ -330,8 +330,10 @@ void fs_dev_disable_sound(void) { } // disable all jack sockets in /dev/shm + EUID_USER(); glob_t globbuf; int globerr = glob("/dev/shm/jack*", GLOB_NOSORT, NULL, &globbuf); + EUID_ROOT(); if (globerr) return; diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 0ed476063..590337da1 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c @@ -395,14 +395,16 @@ void fs_private(void) { } if (chown(homedir, u, g) < 0) errExit("chown"); - fs_logger2("mkdir", homedir); fs_logger2("tmpfs", homedir); } - else + else { // mask user home directory // the directory should be owned by the current user + EUID_USER(); fs_tmpfs(homedir, 1); + EUID_ROOT(); + } selinux_relabel_path(homedir, homedir); } @@ -564,12 +566,13 @@ void fs_private_home_list(void) { int xflag = store_xauthority(); int aflag = store_asoundrc(); - // create /run/firejail/mnt/home directory EUID_ROOT(); + // create /run/firejail/mnt/home directory mkdir_attr(RUN_HOME_DIR, 0755, uid, gid); selinux_relabel_path(RUN_HOME_DIR, homedir); - fs_logger_print(); // save the current log + // save the current log + fs_logger_print(); EUID_USER(); // copy the list of files in the new home directory diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c index 943f275de..7afebed1f 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c @@ -105,6 +105,7 @@ static int whitelist_mkpath(const char* path, mode_t mode) { } static void whitelist_file(int dirfd, const char *relpath, const char *path) { + EUID_ASSERT(); assert(relpath && path); // open mount source, using a file descriptor that refers to the @@ -130,12 +131,9 @@ static void whitelist_file(int dirfd, const char *relpath, const char *path) { } // create mount target as root, except if inside home or run/user/$UID directory - int userprivs = 0; - if ((strncmp(path, cfg.homedir, homedir_len) == 0 && path[homedir_len] == '/') || - (strncmp(path, runuser, runuser_len) == 0 && path[runuser_len] == '/')) { - EUID_USER(); - userprivs = 1; - } + if ((strncmp(path, cfg.homedir, homedir_len) != 0 || path[homedir_len] != '/') && + (strncmp(path, runuser, runuser_len) != 0 || path[runuser_len] != '/')) + EUID_ROOT(); // create path of the mount target int fd2 = whitelist_mkpath(path, 0755); @@ -146,8 +144,7 @@ static void whitelist_file(int dirfd, const char *relpath, const char *path) { if (arg_debug || arg_debug_whitelists) printf("Debug %d: skip whitelist %s\n", __LINE__, path); close(fd); - if (userprivs) - EUID_ROOT(); + EUID_USER(); return; } @@ -166,8 +163,7 @@ static void whitelist_file(int dirfd, const char *relpath, const char *path) { } close(fd); close(fd2); - if (userprivs) - EUID_ROOT(); + EUID_USER(); return; } fd3 = openat(fd2, file, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); @@ -184,19 +180,17 @@ static void whitelist_file(int dirfd, const char *relpath, const char *path) { } close(fd); close(fd2); - if (userprivs) - EUID_ROOT(); + EUID_USER(); return; } - close(fd2); - if (userprivs) - EUID_ROOT(); if (arg_debug || arg_debug_whitelists) printf("Whitelisting %s\n", path); + EUID_ROOT(); if (bind_mount_by_fd(fd, fd3)) errExit("mount bind"); + EUID_USER(); // check the last mount operation MountData *mptr = get_last_mount(); // will do exit(1) if the mount cannot be found #ifdef TEST_MOUNTINFO @@ -219,22 +213,19 @@ static void whitelist_file(int dirfd, const char *relpath, const char *path) { } static void whitelist_symlink(const char *link, const char *target) { + EUID_ASSERT(); assert(link && target); // create files as root, except if inside home or run/user/$UID directory - int userprivs = 0; - if ((strncmp(link, cfg.homedir, homedir_len) == 0 && link[homedir_len] == '/') || - (strncmp(link, runuser, runuser_len) == 0 && link[runuser_len] == '/')) { - EUID_USER(); - userprivs = 1; - } + if ((strncmp(link, cfg.homedir, homedir_len) != 0 || link[homedir_len] != '/') && + (strncmp(link, runuser, runuser_len) != 0 || link[runuser_len] != '/')) + EUID_ROOT(); int fd = whitelist_mkpath(link, 0755); if (fd == -1) { if (arg_debug || arg_debug_whitelists) printf("Debug %d: cannot create symbolic link %s\n", __LINE__, link); - if (userprivs) - EUID_ROOT(); + EUID_USER(); return; } @@ -252,8 +243,7 @@ static void whitelist_symlink(const char *link, const char *target) { printf("Created symbolic link %s -> %s\n", link, target); close(fd); - if (userprivs) - EUID_ROOT(); + EUID_USER(); } static void globbing(const char *pattern) { @@ -330,10 +320,11 @@ static void tmpfs_topdirs(const TopDir *topdirs) { // init tmpfs if (strcmp(topdirs[i].path, "/run") == 0) { // restore /run/firejail directory - if (mkdir(RUN_FIREJAIL_DIR, 0755) == -1) - errExit("mkdir"); + EUID_ROOT(); + mkdir_attr(RUN_FIREJAIL_DIR, 0755, 0, 0); if (bind_mount_fd_to_path(fd, RUN_FIREJAIL_DIR)) errExit("mount bind"); + EUID_USER(); close(fd); fs_logger2("whitelist", RUN_FIREJAIL_DIR); @@ -351,12 +342,14 @@ static void tmpfs_topdirs(const TopDir *topdirs) { errExit("asprintf"); if (strcmp(env, pamtmpdir) == 0) { // create empty user-owned /tmp/user/$UID directory + EUID_ROOT(); 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); + EUID_USER(); } free(pamtmpdir); } @@ -374,11 +367,8 @@ static void tmpfs_topdirs(const TopDir *topdirs) { } // user home directory - if (tmpfs_home) { - EUID_USER(); + if (tmpfs_home) fs_private(); // checks owner if outside /home - EUID_ROOT(); - } // /run/user/$UID directory if (tmpfs_runuser) { @@ -402,6 +392,7 @@ static int reject_topdir(const char *dir) { // keep track of whitelist top level directories by adding them to an array // open each directory static TopDir *add_topdir(const char *dir, TopDir *topdirs, const char *path) { + EUID_ASSERT(); assert(dir && path); // /proc and /sys are not allowed @@ -516,6 +507,8 @@ static char *extract_topdir(const char *path) { } void fs_whitelist(void) { + EUID_ASSERT(); + ProfileEntry *entry = cfg.profile; if (!entry) return; @@ -536,7 +529,6 @@ void fs_whitelist(void) { errExit("calloc"); // verify whitelist files, extract symbolic links, etc. - EUID_USER(); while (entry) { int nowhitelist_flag = 0; @@ -630,7 +622,7 @@ void fs_whitelist(void) { if (!fname) { if (arg_debug || arg_debug_whitelists) { printf("Removed path: %s\n", entry->data); - printf("\texpanded: %s\n", new_name); + printf("\tnew_name: %s\n", new_name); printf("\trealpath: (null)\n"); printf("\t%s\n", strerror(errno)); } @@ -712,7 +704,6 @@ void fs_whitelist(void) { free(nowhitelist); // mount tmpfs on all top level directories - EUID_ROOT(); tmpfs_topdirs(topdirs); // go through profile rules again, and interpret whitelist commands diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 995827fb7..83e50aee2 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c @@ -1004,10 +1004,12 @@ int sandbox(void* sandbox_arg) { // apply the profile file //**************************** // apply all whitelist commands ... + EUID_USER(); fs_whitelist(); // ... followed by blacklist commands fs_blacklist(); // mkdir and mkfile are processed all over again + EUID_ROOT(); //**************************** // nosound/no3d/notv/novideo and fix for pulseaudio 7.0 diff --git a/src/firejail/selinux.c b/src/firejail/selinux.c index 6969e7a3d..fa59882ed 100644 --- a/src/firejail/selinux.c +++ b/src/firejail/selinux.c @@ -21,6 +21,7 @@ #include "firejail.h" #include #include +#include #include #ifndef O_PATH @@ -57,7 +58,17 @@ void selinux_relabel_path(const char *path, const char *inside_path) /* Open the file as O_PATH, to pin it while we determine and adjust the label * Defeat symlink races by not allowing symbolic links */ + int called_as_root = 0; + if (geteuid() == 0) + called_as_root = 1; + if (called_as_root) + EUID_USER(); + fd = safer_openat(-1, path, O_NOFOLLOW|O_CLOEXEC|O_PATH); + + if (called_as_root) + EUID_ROOT(); + if (fd < 0) return; if (fstat(fd, &st) < 0) @@ -68,8 +79,16 @@ void selinux_relabel_path(const char *path, const char *inside_path) if (arg_debug) printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon); - setfilecon_raw(procfs_path, fcon); + if (!called_as_root) + EUID_ROOT(); + + if (setfilecon_raw(procfs_path, fcon) != 0 && arg_debug) + printf("Cannot relabel %s: %s\n", path, strerror(errno)); + + if (!called_as_root) + EUID_USER(); } + freecon(fcon); close: close(fd); diff --git a/src/firejail/util.c b/src/firejail/util.c index 094a68c60..f0df45eb2 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c @@ -459,31 +459,21 @@ int is_dir(const char *fname) { if (*fname == '\0') return 0; - int called_as_root = 0; - if (geteuid() == 0) - called_as_root = 1; - - if (called_as_root) - EUID_USER(); - // if fname doesn't end in '/', add one int rv; struct stat s; if (fname[strlen(fname) - 1] == '/') - rv = stat(fname, &s); + rv = stat_as_user(fname, &s); else { char *tmp; if (asprintf(&tmp, "%s/", fname) == -1) { fprintf(stderr, "Error: cannot allocate memory, %s:%d\n", __FILE__, __LINE__); errExit("asprintf"); } - rv = stat(tmp, &s); + rv = stat_as_user(tmp, &s); free(tmp); } - if (called_as_root) - EUID_ROOT(); - if (rv == -1) return 0; -- cgit v1.2.3-54-g00ecf