From 8c2b460d143d8dda4a86b826c0920918aa15f1f7 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Fri, 18 Nov 2016 09:11:30 -0500 Subject: fcopy part 4 --- src/fcopy/main.c | 9 +-- src/firejail/firejail.h | 1 - src/firejail/fs_bin.c | 171 +++++---------------------------------------- src/firejail/fs_etc.c | 16 ++--- src/firejail/fs_home.c | 67 +++++++++--------- src/firejail/fs_hostname.c | 28 +++----- src/firejail/main.c | 1 - src/firejail/profile.c | 1 - src/firejail/sandbox.c | 1 - src/firemon/netstats.c | 3 + src/firemon/top.c | 3 + 11 files changed, 80 insertions(+), 221 deletions(-) (limited to 'src') diff --git a/src/fcopy/main.c b/src/fcopy/main.c index 56d297c9a..e3a04a515 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c @@ -244,7 +244,7 @@ static void duplicate_file(const char *src, const char *dest, struct stat *s) { } static void duplicate_link(const char *src, const char *dest, struct stat *s) { - char *rsrc = check(src); + char *rsrc = check(src); // we drop the result and use the original name char *rdest = check(dest); uid_t uid = s->st_uid; gid_t gid = s->st_gid; @@ -252,7 +252,8 @@ static void duplicate_link(const char *src, const char *dest, struct stat *s) { // build destination file name char *name; - char *ptr = strrchr(rsrc, '/'); +// char *ptr = strrchr(rsrc, '/'); + char *ptr = strrchr(src, '/'); ptr++; if (asprintf(&name, "%s/%s", rdest, ptr) == -1) errExit("asprintf"); @@ -272,7 +273,7 @@ static void usage(void) { } int main(int argc, char **argv) { -//#if 0 +#if 0 { //system("cat /proc/self/status"); int i; @@ -280,7 +281,7 @@ for (i = 0; i < argc; i++) printf("*%s* ", argv[i]); printf("\n"); } -//#endif +#endif if (argc != 3) { fprintf(stderr, "Error fcopy: files missing\n"); usage(); diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 80627fda8..2562094d3 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -587,7 +587,6 @@ void pulseaudio_init(void); void pulseaudio_disable(void); // fs_bin.c -void fs_check_bin_list(void); void fs_private_bin_list(void); // protocol.c diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c index 6cc1bf3ab..421df717d 100644 --- a/src/firejail/fs_bin.c +++ b/src/firejail/fs_bin.c @@ -39,7 +39,6 @@ static char *paths[] = { // return 1 if found, 0 if not found static char *check_dir_or_file(const char *name) { assert(name); - invalid_filename(name); struct stat s; char *fname = NULL; @@ -94,68 +93,13 @@ static char *check_dir_or_file(const char *name) { return paths[i]; } -void fs_check_bin_list(void) { - EUID_ASSERT(); - if (strstr(cfg.bin_private_keep, "..")) { - fprintf(stderr, "Error: invalid private bin list\n"); +static void duplicate(char *fname) { + if (*fname == '~' || *fname == '/' || strstr(fname, "..")) { + fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname); exit(1); } - - char *dlist = strdup(cfg.bin_private_keep); - if (!dlist) - errExit("strdup"); - - // create a new list removing files not found - char *newlist = malloc(strlen(dlist) + 1 + 1); // +',' + '\0' - if (!newlist) - errExit("malloc"); - *newlist = '\0'; - char *newlistptr = newlist; - - // check the first file - char *ptr = strtok(dlist, ","); - int notfound = 0; - if (check_dir_or_file(ptr)) { - // file found, copy the name in the new list - strcpy(newlistptr, ptr); - strcat(newlistptr, ","); - newlistptr += strlen(newlistptr); - } - else - notfound = 1; - - // check the rest of the list - while ((ptr = strtok(NULL, ",")) != NULL) { - if (check_dir_or_file(ptr)) { - // file found, copy the name in the new list - strcpy(newlistptr, ptr); - strcat(newlistptr, ","); - newlistptr += strlen(newlistptr); - } - else - notfound = 1; - } - - if (*newlist == '\0') { -// fprintf(stderr, "Warning: no --private-bin list executable found, option disabled\n"); -// cfg.bin_private_keep = NULL; -// arg_private_bin = 0; - free(newlist); - } - else { - ptr = strrchr(newlist, ','); - assert(ptr); - *ptr = '\0'; - if (notfound && !arg_quiet) - fprintf(stderr, "Warning: not all executables from --private-bin list were found. The current list is %s\n", newlist); - - cfg.bin_private_keep = newlist; - } - - free(dlist); -} + invalid_filename(fname); -static void duplicate(char *fname) { char *path = check_dir_or_file(fname); if (!path) return; @@ -165,44 +109,9 @@ static void duplicate(char *fname) { if (asprintf(&full_path, "%s/%s", path, fname) == -1) errExit("asprintf"); - char *actual_path = realpath(full_path, NULL); - if (actual_path) { - // if the file is a symbolic link not under path, make a symbolic link - if (is_link(full_path) && strncmp(actual_path, path, strlen(path))) { - char *lnkname; - if (asprintf(&lnkname, "%s/%s", RUN_BIN_DIR, fname) == -1) - errExit("asprintf"); - int rv = symlink(actual_path, lnkname); - if (rv) - fprintf(stderr, "Warning cannot create symbolic link %s\n", lnkname); - else if (arg_debug) - printf("Created symbolic link %s -> %s\n", lnkname, actual_path); - free(lnkname); - } - else { - // copy the file - if (arg_debug) - printf("running: %s -a %s %s/%s", RUN_CP_COMMAND, actual_path, RUN_BIN_DIR, fname); - - pid_t child = fork(); - if (child < 0) - errExit("fork"); - if (child == 0) { - char *f; - if (asprintf(&f, "%s/%s", RUN_BIN_DIR, fname) == -1) - errExit("asprintf"); - clearenv(); - execlp(RUN_CP_COMMAND, RUN_CP_COMMAND, "-a", actual_path, f, NULL); - perror("execlp"); - _exit(1); - } - // wait for the child to finish - waitpid(child, NULL, 0); - - } - free(actual_path); - } - + // copy the file + sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, full_path, RUN_BIN_DIR); + fs_logger2("clone", fname); free(full_path); } @@ -214,42 +123,20 @@ void fs_private_bin_list(void) { // create /run/firejail/mnt/bin directory mkdir_attr(RUN_BIN_DIR, 0755, 0, 0); - // copy the list of files in the new etc directory - // using a new child process without root privileges - fs_logger_print(); // save the current log - pid_t child = fork(); - if (child < 0) - errExit("fork"); - if (child == 0) { - if (arg_debug) - printf("Copying files in the new home:\n"); + if (arg_debug) + printf("Copying files in the new bin directory\n"); - // elevate privileges - files in the new /bin directory belong to root - if (setreuid(0, 0) < 0) - errExit("setreuid"); - if (setregid(0, 0) < 0) - errExit("setregid"); - - // copy the list of files in the new home directory - char *dlist = strdup(private_list); - if (!dlist) - errExit("strdup"); - + // copy the list of files in the new home directory + char *dlist = strdup(private_list); + if (!dlist) + errExit("strdup"); - char *ptr = strtok(dlist, ","); + char *ptr = strtok(dlist, ","); + duplicate(ptr); + while ((ptr = strtok(NULL, ",")) != NULL) duplicate(ptr); - - while ((ptr = strtok(NULL, ",")) != NULL) - duplicate(ptr); - free(dlist); + free(dlist); fs_logger_print(); -#ifdef HAVE_GCOV - __gcov_flush(); -#endif - _exit(0); - } - // wait for the child to finish - waitpid(child, NULL, 0); // mount-bind int i = 0; @@ -265,29 +152,5 @@ void fs_private_bin_list(void) { } i++; } - - // log cloned files - char *dlist = strdup(private_list); - if (!dlist) - errExit("strdup"); - - - char *ptr = strtok(dlist, ","); - while (ptr) { - i = 0; - while (paths[i]) { - struct stat s; - if (stat(paths[i], &s) == 0) { - char *fname; - if (asprintf(&fname, "%s/%s", paths[i], ptr) == -1) - errExit("asprintf"); - fs_logger2("clone", fname); - free(fname); - } - i++; - } - ptr = strtok(NULL, ","); - } - free(dlist); } diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c index 7d4ffa938..80329d5ba 100644 --- a/src/firejail/fs_etc.c +++ b/src/firejail/fs_etc.c @@ -26,11 +26,8 @@ // return 0 if file not found, 1 if found static int check_dir_or_file(const char *fname) { assert(fname); - invalid_filename(fname); struct stat s; - if (arg_debug) - printf("Checking %s\n", fname); if (stat(fname, &s) == -1) { if (arg_debug) printf("Warning: file %s not found.\n", fname); @@ -51,6 +48,12 @@ errexit: } static void duplicate(char *fname) { + if (*fname == '~' || *fname == '/' || strstr(fname, "..")) { + fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname); + exit(1); + } + invalid_filename(fname); + char *src; if (asprintf(&src, "/etc/%s", fname) == -1) errExit("asprintf"); @@ -61,7 +64,6 @@ static void duplicate(char *fname) { return; } - struct stat s; if (stat(src, &s) == 0 && S_ISDIR(s.st_mode)) { // create the directory in RUN_ETC_DIR @@ -84,12 +86,6 @@ void fs_private_etc_list(void) { char *private_list = cfg.etc_private_keep; assert(private_list); - struct stat s; - if (stat("/etc", &s) == -1) { - fprintf(stderr, "Error: cannot find user /etc directory\n"); - exit(1); - } - // create /run/firejail/mnt/etc directory mkdir_attr(RUN_ETC_DIR, 0755, 0, 0); fs_logger("tmpfs /etc"); diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index d8cd9ce4d..1612da5d3 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c @@ -212,12 +212,6 @@ void fs_private_homedir(void) { uid_t u = getuid(); gid_t g = getgid(); - struct stat s; - if (stat(homedir, &s) == -1) { - fprintf(stderr, "Error: cannot find user home directory\n"); - exit(1); - } - // mount bind private_homedir on top of homedir if (arg_debug) @@ -351,11 +345,9 @@ void fs_check_private_dir(void) { //*********************************************************************************** static char *check_dir_or_file(const char *name) { assert(name); - struct stat s; // basic checks invalid_filename(name); - if (arg_debug) printf("Private home: checking %s\n", name); @@ -372,28 +364,44 @@ static char *check_dir_or_file(const char *name) { fname = tmp; } - // check the file is in user home directory, a full home directory is not allowed - char *rname = realpath(fname, NULL); - if (!rname || - strncmp(rname, cfg.homedir, strlen(cfg.homedir)) != 0 || - strcmp(rname, cfg.homedir) == 0) { - fprintf(stderr, "Error: invalid file %s\n", name); - exit(1); + // we allow only files in user home directory or symbolic links to files or directories owned by the user + struct stat s; + if (lstat(fname, &s) == 0 && S_ISLNK(s.st_mode)) { + if (stat(fname, &s) == 0) { + if (s.st_uid != getuid()) { + fprintf(stderr, "Error: symbolic link %s to file or directory not owned by the user\n", fname); + exit(1); + } + return fname; + } + else { + fprintf(stderr, "Error: invalid file %s\n", name); + exit(1); + } } - - // only top files and directories in user home are allowed - char *ptr = rname + strlen(cfg.homedir); - assert(*ptr != '\0'); - ptr = strchr(++ptr, '/'); - if (ptr) { - if (*ptr != '\0') { - fprintf(stderr, "Error: only top files and directories in user home are allowed\n"); + else { + // check the file is in user home directory, a full home directory is not allowed + char *rname = realpath(fname, NULL); + if (!rname || + strncmp(rname, cfg.homedir, strlen(cfg.homedir)) != 0 || + strcmp(rname, cfg.homedir) == 0) { + fprintf(stderr, "Error: invalid file %s\n", name); exit(1); } + + // only top files and directories in user home are allowed + char *ptr = rname + strlen(cfg.homedir); + assert(*ptr != '\0'); + ptr = strchr(++ptr, '/'); + if (ptr) { + if (*ptr != '\0') { + fprintf(stderr, "Error: only top files and directories in user home are allowed\n"); + exit(1); + } + } + free(fname); + return rname; } - - free(fname); - return rname; } static void duplicate(char *name) { @@ -405,7 +413,7 @@ static void duplicate(char *name) { assert(strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0); struct stat s; - if (stat(fname, &s) == -1) { + if (lstat(fname, &s) == -1) { free(fname); return; } @@ -445,11 +453,6 @@ void fs_private_home_list(void) { uid_t uid = getuid(); gid_t gid = getgid(); - struct stat s; - if (stat(homedir, &s) == -1) { - fprintf(stderr, "Error: cannot find user home directory\n"); - exit(1); - } // create /run/firejail/mnt/home directory mkdir_attr(RUN_HOME_DIR, 0755, uid, gid); diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c index 04197eb8f..dcf06fc6f 100644 --- a/src/firejail/fs_hostname.c +++ b/src/firejail/fs_hostname.c @@ -33,15 +33,7 @@ void fs_hostname(const char *hostname) { if (arg_debug) printf("Creating a new /etc/hostname file\n"); - FILE *fp = fopen(RUN_HOSTNAME_FILE, "w"); - if (!fp) { - fprintf(stderr, "Error: cannot create %s\n", RUN_HOSTNAME_FILE); - exit(1); - } - fprintf(fp, "%s\n", hostname); - // mode and owner - SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); - fclose(fp); + create_empty_file_as_root(RUN_HOSTNAME_FILE, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); // bind-mount the file on top of /etc/hostname if (mount(RUN_HOSTNAME_FILE, "/etc/hostname", NULL, MS_BIND|MS_REC, NULL) < 0) @@ -56,15 +48,12 @@ void fs_hostname(const char *hostname) { // copy /etc/host into our new file, and modify it on the fly /* coverity[toctou] */ FILE *fp1 = fopen("/etc/hosts", "r"); - if (!fp1) { - fprintf(stderr, "Error: cannot open /etc/hosts\n"); - exit(1); - } + if (!fp1) + goto errexit; + FILE *fp2 = fopen(RUN_HOSTS_FILE, "w"); - if (!fp2) { - fprintf(stderr, "Error: cannot create %s\n", RUN_HOSTS_FILE); - exit(1); - } + if (!fp2) + goto errexit; char buf[4096]; int done = 0; @@ -92,6 +81,11 @@ void fs_hostname(const char *hostname) { errExit("mount bind /etc/hosts"); fs_logger("create /etc/hosts"); } + return; + +errexit: + fprintf(stderr, "Error: cannot create hostname file\n"); + exit(1); } void fs_resolvconf(void) { diff --git a/src/firejail/main.c b/src/firejail/main.c index 5bfa04cc9..ff7b762cd 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -1634,7 +1634,6 @@ int main(int argc, char **argv) { exit(1); } arg_private_bin = 1; - fs_check_bin_list(); } else if (strcmp(argv[i], "--private-tmp") == 0) { arg_private_tmp = 1; diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 693b1dc30..688fa9609 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c @@ -745,7 +745,6 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { if (strncmp(ptr, "private-bin ", 12) == 0) { cfg.bin_private_keep = ptr + 12; arg_private_bin = 1; - fs_check_bin_list(); return 0; } diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 109daf552..c2e053b0c 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c @@ -696,7 +696,6 @@ int sandbox(void* sandbox_arg) { if (asprintf(&tmp, "%s,xauth", cfg.bin_private_keep) == -1) errExit("asprintf"); cfg.bin_private_keep = tmp; - fs_check_bin_list(); EUID_ROOT(); } fs_private_bin_list(); diff --git a/src/firemon/netstats.c b/src/firemon/netstats.c index 3c020d630..534d783cb 100644 --- a/src/firemon/netstats.c +++ b/src/firemon/netstats.c @@ -216,6 +216,9 @@ void netstats(void) { print_proc(i, itv, col); } } +#ifdef HAVE_GCOV + __gcov_flush(); +#endif } } diff --git a/src/firemon/top.c b/src/firemon/top.c index b804761dd..94271523c 100644 --- a/src/firemon/top.c +++ b/src/firemon/top.c @@ -292,6 +292,9 @@ void top(void) { } } head_print(col, row); +#ifdef HAVE_GCOV + __gcov_flush(); +#endif } } -- cgit v1.2.3-54-g00ecf