From 6fc51f43e88605682bd307515090df51b871b717 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Wed, 9 Jan 2019 09:42:55 -0500 Subject: mainline merge: fix join/seccomp #2296 --- src/firejail/firejail.h | 3 +- src/firejail/join.c | 65 ++++++++++++++++++-------------- src/firejail/seccomp.c | 77 ++++++++++++++++++++++++++++++++++---- test/filters/seccomp-run-files.exp | 4 +- 4 files changed, 110 insertions(+), 39 deletions(-) diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 00c6cd8f3..fcaee18a2 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -55,7 +55,7 @@ #define RUN_LIB_FILE "/run/firejail/mnt/libfiles" #define RUN_DNS_ETC "/run/firejail/mnt/dns-etc" - +#define RUN_SECCOMP_LIST "/run/firejail/mnt/seccomp.list" // list of seccomp files installed #define RUN_SECCOMP_PROTOCOL "/run/firejail/mnt/seccomp.protocol" // protocol filter #define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp" // configured filter #define RUN_SECCOMP_32 "/run/firejail/mnt/seccomp.32" // 32bit arch filter installed on 64bit architectures @@ -545,6 +545,7 @@ void fs_private_home_list(void); // seccomp.c +void seccomp_load_file_list(void); char *seccomp_check_list(const char *str); int seccomp_install_filters(void); int seccomp_load(const char *fname); diff --git a/src/firejail/join.c b/src/firejail/join.c index 731842275..28fd1b290 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c @@ -22,6 +22,8 @@ #include #include #include +#include + #include #include @@ -71,8 +73,10 @@ static void extract_nogroups(pid_t pid) { errExit("asprintf"); struct stat s; - if (stat(fname, &s) == -1) + if (stat(fname, &s) == -1) { + free(fname); return; + } arg_nogroups = 1; free(fname); @@ -84,8 +88,10 @@ static void extract_cpu(pid_t pid) { errExit("asprintf"); struct stat s; - if (stat(fname, &s) == -1) + if (stat(fname, &s) == -1) { + free(fname); return; + } // there is a CPU_CFG file, load it! load_cpu(fname); @@ -93,7 +99,7 @@ static void extract_cpu(pid_t pid) { } -static void extract_caps_seccomp(pid_t pid) { +static void extract_caps(pid_t pid) { // open stat file char *file; if (asprintf(&file, "/proc/%u/status", pid) == -1) { @@ -101,32 +107,35 @@ static void extract_caps_seccomp(pid_t pid) { exit(1); } FILE *fp = fopen(file, "r"); - if (!fp) { - free(file); - fprintf(stderr, "Error: cannot open stat file for process %u\n", pid); - exit(1); - } + if (!fp) + goto errexit; char buf[BUFLEN]; while (fgets(buf, BUFLEN - 1, fp)) { - if (strncmp(buf, "Seccomp:", 8) == 0) { - char *ptr = buf + 8; - int val; - sscanf(ptr, "%d", &val); - if (val == 2) - apply_seccomp = 1; - break; - } - else if (strncmp(buf, "CapBnd:", 7) == 0) { + if (strncmp(buf, "CapBnd:", 7) == 0) { char *ptr = buf + 7; unsigned long long val; - sscanf(ptr, "%llx", &val); + if (sscanf(ptr, "%llx", &val) != 1) + goto errexit; apply_caps = 1; caps = val; } + else if (strncmp(buf, "NoNewPrivs:", 11) == 0) { + char *ptr = buf + 11; + int val; + if (sscanf(ptr, "%d", &val) != 1) + goto errexit; + if (val) + arg_nonewprivs = 1; + } } fclose(fp); free(file); + return; + +errexit: + fprintf(stderr, "Error: cannot read stat file for process %u\n", pid); + exit(1); } static void extract_user_namespace(pid_t pid) { @@ -187,7 +196,7 @@ pid_t switch_to_child(pid_t pid) { char *comm = pid_proc_comm(pid); if (!comm) { if (errno == ENOENT) { - fprintf(stderr, "Error: cannot find process with id %d\n", pid); + fprintf(stderr, "Error: cannot find process with pid %d\n", pid); exit(1); } else { @@ -240,7 +249,7 @@ void join(pid_t pid, int argc, char **argv, int index) { EUID_ROOT(); // in user mode set caps seccomp, cpu, cgroup, etc if (getuid() != 0) { - extract_caps_seccomp(pid); + extract_caps(pid); extract_cpu(pid); extract_nogroups(pid); extract_user_namespace(pid); @@ -309,15 +318,8 @@ void join(pid_t pid, int argc, char **argv, int index) { if (apply_caps == 1) // not available for uid 0 caps_set(caps); #ifdef HAVE_SECCOMP - // read cfg.protocol from file if (getuid() != 0) - protocol_filter_load(RUN_PROTOCOL_CFG); - if (cfg.protocol) // not available for uid 0 - seccomp_load(RUN_SECCOMP_PROTOCOL); // install filter - - // set seccomp filter - if (apply_seccomp == 1) // not available for uid 0 - seccomp_load(RUN_SECCOMP_CFG); + seccomp_load_file_list(); #endif // mount user namespace or drop privileges @@ -333,6 +335,13 @@ void join(pid_t pid, int argc, char **argv, int index) { caps_set(caps); } + // set nonewprivs + if (arg_nonewprivs == 1) { // not available for uid 0 + int rv = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); + if (arg_debug && rv == 0) + printf("NO_NEW_PRIVS set\n"); + } + EUID_USER(); // set nice if (arg_nice) { diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index 7be7b3950..a5323d840 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c @@ -89,6 +89,41 @@ int seccomp_install_filters(void) { return r; } +static void seccomp_save_file_list(const char *fname) { + assert(fname); + + FILE *fp = fopen(RUN_SECCOMP_LIST, "a+"); + if (!fp) + errExit("fopen"); + + fprintf(fp, "%s\n", fname); + fclose(fp); + int rv = chown(RUN_SECCOMP_LIST, getuid(), getgid()); + (void) rv; +} + +#define MAXBUF 4096 +static int load_file_list_flag = 0; +void seccomp_load_file_list(void) { + FILE *fp = fopen(RUN_SECCOMP_LIST, "r"); + if (!fp) + return; // no seccomp configuration whatsoever + + load_file_list_flag = 1; + char buf[MAXBUF]; + while (fgets(buf, MAXBUF, fp)) { + // clean '\n' + char *ptr = strchr(buf, '\n'); + if (ptr) + *ptr = '\0'; + seccomp_load(buf); + } + + fclose(fp); + load_file_list_flag = 0; +} + + int seccomp_load(const char *fname) { assert(fname); @@ -131,6 +166,10 @@ int seccomp_load(const char *fname) { PATH_FSEC_PRINT, fname); } + // save the file name in seccomp list + if (!load_file_list_flag) + seccomp_save_file_list(fname); + return 0; errexit: fprintf(stderr, "Error: cannot read %s\n", fname); @@ -314,23 +353,45 @@ void seccomp_print_filter(pid_t pid) { } } - // find the seccomp filter + // find the seccomp list file EUID_ROOT(); char *fname; - if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_SECCOMP_CFG) == -1) + if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_SECCOMP_LIST) == -1) errExit("asprintf"); struct stat s; - if (stat(fname, &s) == -1) { - printf("Cannot access seccomp filter.\n"); - exit(1); - } + if (stat(fname, &s) == -1) + goto errexit; - // read and print the filter - run this as root, the user doesn't have access - sbox_run(SBOX_ROOT | SBOX_SECCOMP, 2, PATH_FSEC_PRINT, fname); + FILE *fp = fopen(fname, "r"); + if (!fp) + goto errexit; free(fname); + char buf[MAXBUF]; + while (fgets(buf, MAXBUF, fp)) { + // clean '\n' + char *ptr = strchr(buf, '\n'); + if (ptr) + *ptr = '\0'; + + if (asprintf(&fname, "/proc/%d/root%s", pid, buf) == -1) + errExit("asprintf"); + printf("FILE: %s\n", fname); fflush(0); + + // read and print the filter - run this as root, the user doesn't have access + sbox_run(SBOX_ROOT | SBOX_SECCOMP, 2, PATH_FSEC_PRINT, fname); + fflush(0); + + printf("\n"); fflush(0); + free(fname); + } + fclose(fp); exit(0); + +errexit: + printf("Cannot access seccomp filter.\n"); + exit(1); } #endif // HAVE_SECCOMP diff --git a/test/filters/seccomp-run-files.exp b/test/filters/seccomp-run-files.exp index 7c436b664..7a1345902 100755 --- a/test/filters/seccomp-run-files.exp +++ b/test/filters/seccomp-run-files.exp @@ -24,7 +24,7 @@ after 100 send -- "ls -l /run/firejail/mnt | grep -c seccomp\r" expect { timeout {puts "TESTING ERROR 3\n";exit} - "4" + "5" } send -- "exit\r" sleep 1 @@ -90,7 +90,7 @@ after 100 send -- "ls -l /run/firejail/mnt | grep -c seccomp\r" expect { timeout {puts "TESTING ERROR 18\n";exit} - "5" + "6" } send -- "exit\r" sleep 1 -- cgit v1.2.3-54-g00ecf