From 98159c098b6afedfed20eecdc80719dae1f914ff Mon Sep 17 00:00:00 2001 From: netblue30 Date: Wed, 16 Nov 2016 16:40:12 -0500 Subject: fcopy part 2 --- src/fcopy/main.c | 36 +++---- src/firejail/firejail.h | 4 +- src/firejail/fs_etc.c | 31 ------ src/firejail/fs_home.c | 269 ++++++++++-------------------------------------- src/firejail/main.c | 2 - src/firejail/profile.c | 2 - src/firejail/util.c | 7 +- 7 files changed, 74 insertions(+), 277 deletions(-) (limited to 'src') diff --git a/src/fcopy/main.c b/src/fcopy/main.c index 4437b90e5..82d829bba 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c @@ -130,10 +130,16 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str if (size_limit_reached) return 0; + char *outfname; if (asprintf(&outfname, "%s%s", outpath, infname + strlen(inpath)) == -1) errExit("asprintf"); +//printf("outpaht %s\n", outpath); +//printf("inpath %s\n", inpath); +//printf("infname %s\n", infname); +//printf("outfname %s\n\n", outfname); + // don't copy it if we already have the file struct stat s; if (stat(outfname, &s) == 0) { @@ -265,7 +271,7 @@ static void duplicate_link(const char *src, const char *dest, struct stat *s) { static void usage(void) { printf("Usage: fcopy src dest\n"); printf("Copy src file in dest directory. If src is a directory, copy all the files in\n"); - printf("src recoursively\n"); + printf("src recoursively. If the destination directory does not exist, it will be created.\n"); } int main(int argc, char **argv) { @@ -276,25 +282,16 @@ int i; 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(); exit(1); } - int i; - int index = 1; - for (i = 1; i < (argc - 2); i++) { - if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { - usage(); - return 0; - } - } - // check the two files; remove ending / - char *src = argv[index]; + char *src = argv[1]; int len = strlen(src); if (src[len - 1] == '/') src[len - 1] = '\0'; @@ -303,7 +300,7 @@ printf("\n"); exit(1); } - char *dest = argv[index + 1]; + char *dest = argv[2]; len = strlen(dest); if (dest[len - 1] == '/') dest[len - 1] = '\0'; @@ -313,14 +310,11 @@ printf("\n"); } - // the destination should be a directory; remove ending / + // the destination should be a directory; struct stat s; - if (stat(dest, &s) == -1) { - fprintf(stderr, "Error fcopy: cannot find destination directory\n"); - exit(1); - } - if (S_ISDIR(s.st_mode) == -1) { - fprintf(stderr, "Error fcopy: the destination should be a directory\n"); + if (stat(dest, &s) == -1 || + !S_ISDIR(s.st_mode)) { + fprintf(stderr, "Error fcopy: invalid destination directory\n"); exit(1); } diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index d7ba539e6..80627fda8 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -490,8 +490,6 @@ void fs_private_template(void); void fs_check_private_dir(void); // check new private template home directory (--private-template= option) exit if it fails void fs_check_private_template(void); -// check directory list specified by user (--private-home option) - exit if it fails -void fs_check_home_list(void); void fs_private_home_list(void); @@ -557,7 +555,6 @@ void network_del_run_file(pid_t pid); void network_set_run_file(pid_t pid); // fs_etc.c -void fs_check_etc_list(void); void fs_private_etc_list(void); // no_sandbox.c @@ -681,6 +678,7 @@ void build_cmdline(char **command_line, char **window_title, int argc, char **ar #define PATH_FNET (LIBDIR "/firejail/fnet") #define PATH_FIREMON (PREFIX "/bin/firemon") #define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp") +#define PATH_FCOPY (LIBDIR "/firejail/fcopy") // bitmapped filters for sbox_run #define SBOX_ROOT (1 << 0) // run the sandbox as root #define SBOX_USER (1 << 1) // run the sandbox as a regular user diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c index 7e18840fd..6a70d482c 100644 --- a/src/firejail/fs_etc.c +++ b/src/firejail/fs_etc.c @@ -62,37 +62,6 @@ errexit: exit(1); } -void fs_check_etc_list(void) { - EUID_ASSERT(); - if (strstr(cfg.etc_private_keep, "..")) { - fprintf(stderr, "Error: invalid private etc list\n"); - exit(1); - } - - char *dlist = strdup(cfg.etc_private_keep); - if (!dlist) - errExit("strdup"); - - // build a new list only with the files found - char *newlist = malloc(strlen(cfg.etc_private_keep) + 1); - if (!newlist) - errExit("malloc"); - *newlist = '\0'; - - char *ptr = strtok(dlist, ","); - if (check_dir_or_file(ptr)) - strcat(newlist, ptr); - while ((ptr = strtok(NULL, ",")) != NULL) { - if (check_dir_or_file(ptr)) { - strcat(newlist, ","); - strcat(newlist, ptr); - } - } - cfg.etc_private_keep = newlist; - - free(dlist); -} - static void duplicate(char *fname) { // copy the file if (arg_debug) diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 242482d26..d8cd9ce4d 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c @@ -28,7 +28,7 @@ #include #include #include -#include +//#include static void skel(const char *homedir, uid_t u, gid_t g) { char *fname; @@ -349,106 +349,6 @@ void fs_check_private_dir(void) { //*********************************************************************************** // --private-home //*********************************************************************************** -#define PRIVATE_COPY_LIMIT (500 * 1024 *1024) -static int size_limit_reached = 0; -static unsigned file_cnt = 0; -static unsigned size_cnt = 0; -static char *check_dir_or_file(const char *name); - -int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *sftw) { - (void) st; - (void) sftw; - if (size_limit_reached) - return 0; - - struct stat s; - char *dest; - if (asprintf(&dest, "%s%s", RUN_HOME_DIR, path + strlen(cfg.homedir)) == -1) - errExit("asprintf"); - - // don't copy it if we already have the file - if (stat(dest, &s) == 0) { - free(dest); - return 0; - } - - // extract mode and ownership - if (stat(path, &s) != 0) { - free(dest); - return 0; - } - - // check uid - if (s.st_uid != firejail_uid || s.st_gid != firejail_gid) { - free(dest); - return 0; - } - - if ((s.st_size + size_cnt) > PRIVATE_COPY_LIMIT) { - size_limit_reached = 1; - free(dest); - return 0; - } - - file_cnt++; - size_cnt += s.st_size; - - if(ftype == FTW_F) - copy_file(path, dest, firejail_uid, firejail_gid, s.st_mode); - else if (ftype == FTW_D) { - if (mkdir(dest, s.st_mode) == -1) - errExit("mkdir"); - if (set_perms(dest, firejail_uid, firejail_gid, s.st_mode)) - errExit("set_perms"); -#if 0 -struct stat s2; -if (stat(dest, &s2) == 0) { - printf("%s\t", dest); - printf((S_ISDIR(s.st_mode)) ? "d" : "-"); - printf((s.st_mode & S_IRUSR) ? "r" : "-"); - printf((s.st_mode & S_IWUSR) ? "w" : "-"); - printf((s.st_mode & S_IXUSR) ? "x" : "-"); - printf((s.st_mode & S_IRGRP) ? "r" : "-"); - printf((s.st_mode & S_IWGRP) ? "w" : "-"); - printf((s.st_mode & S_IXGRP) ? "x" : "-"); - printf((s.st_mode & S_IROTH) ? "r" : "-"); - printf((s.st_mode & S_IWOTH) ? "w" : "-"); - printf((s.st_mode & S_IXOTH) ? "x" : "-"); - printf("\n"); -} -#endif - - fs_logger2("clone", path); - } - - free(dest); - return(0); -} - -static void duplicate(char *name) { - char *fname = check_dir_or_file(name); - - if (arg_debug) - printf("Private home: duplicating %s\n", fname); - assert(strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0); - - struct stat s; - if (stat(fname, &s) == -1) { - free(fname); - return; - } - - if(nftw(fname, fs_copydir, 1, FTW_PHYS) != 0) { - fprintf(stderr, "Error: unable to copy template dir\n"); - exit(1); - } - fs_logger_print(); // save the current log - - free(fname); -} - - - static char *check_dir_or_file(const char *name) { assert(name); struct stat s; @@ -461,10 +361,7 @@ static char *check_dir_or_file(const char *name) { // expand home directory char *fname = expand_home(name, cfg.homedir); - if (!fname) { - fprintf(stderr, "Error: file %s not found.\n", name); - exit(1); - } + assert(fname); // If it doesn't start with '/', it must be relative to homedir if (fname[0] != '/') { @@ -475,31 +372,19 @@ static char *check_dir_or_file(const char *name) { fname = tmp; } - // check the file is in user home directory + // check the file is in user home directory, a full home directory is not allowed char *rname = realpath(fname, NULL); - if (!rname) { + 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); } - if (strncmp(rname, cfg.homedir, strlen(cfg.homedir)) != 0) { - fprintf(stderr, "Error: file %s is not in user home directory\n", name); - exit(1); - } - - // a full home directory is not allowed - if (strcmp(rname, cfg.homedir) == 0) { - fprintf(stderr, "Error: invalid directory %s\n", rname); - exit(1); - } // only top files and directories in user home are allowed char *ptr = rname + strlen(cfg.homedir); - if (*ptr == '\0') { - fprintf(stderr, "Error: invalid file %s\n", name); - exit(1); - } - ptr++; - ptr = strchr(ptr, '/'); + 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"); @@ -507,55 +392,42 @@ static char *check_dir_or_file(const char *name) { } } - if (stat(fname, &s) == -1) { - fprintf(stderr, "Error: file %s not found.\n", fname); - exit(1); - } - - // check uid - uid_t uid = getuid(); - gid_t gid = getgid(); - if (s.st_uid != uid || s.st_gid != gid) { - fprintf(stderr, "Error: only files or directories created by the current user are allowed.\n"); - exit(1); - } - - // dir or regular file - if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode)) { - free(fname); - return rname; // regular exit from the function - } - - fprintf(stderr, "Error: invalid file type, %s.\n", fname); - exit(1); + free(fname); + return rname; } +static void duplicate(char *name) { + char *fname = check_dir_or_file(name); + char *dest = RUN_HOME_DIR; -// check directory list specified by user (--private-home option) - exit if it fails -void fs_check_home_list(void) { - if (strstr(cfg.home_private_keep, "..")) { - fprintf(stderr, "Error: invalid private-home list\n"); - exit(1); - } - - char *dlist = strdup(cfg.home_private_keep); - if (!dlist) - errExit("strdup"); - - char *ptr = strtok(dlist, ","); - char *tmp = check_dir_or_file(ptr); - free(tmp); + if (arg_debug) + printf("Private home: duplicating %s\n", fname); + assert(strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0); - while ((ptr = strtok(NULL, ",")) != NULL) { - tmp = check_dir_or_file(ptr); - free(tmp); + struct stat s; + if (stat(fname, &s) == -1) { + free(fname); + return; + } + else if (S_ISDIR(s.st_mode)) { + // create the directory in RUN_HOME_DIR + char *name; + char *ptr = strrchr(fname, '/'); + ptr++; + if (asprintf(&name, "%s/%s", RUN_HOME_DIR, ptr) == -1) + errExit("asprintf"); + mkdir_attr(name, 0755, getuid(), getgid()); + sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, name); + free(name); } + else + sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, RUN_HOME_DIR); + fs_logger2("clone", fname); + fs_logger_print(); // save the current log - free(dlist); + free(fname); } - - // private mode (--private-home=list): // mount homedir on top of /home/user, // tmpfs on top of /root in nonroot mode, @@ -571,8 +443,8 @@ void fs_private_home_list(void) { int xflag = store_xauthority(); int aflag = store_asoundrc(); - uid_t u = firejail_uid; - gid_t g = firejail_gid; + 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"); @@ -580,59 +452,24 @@ void fs_private_home_list(void) { } // create /run/firejail/mnt/home directory - int rv = mkdir(RUN_HOME_DIR, 0755); - if (rv == -1) - errExit("mkdir"); - if (set_perms(RUN_HOME_DIR, u, g, 0755)) - errExit("set_perms"); - ASSERT_PERMS(RUN_HOME_DIR, u, g, 0755); - + mkdir_attr(RUN_HOME_DIR, 0755, uid, gid); fs_logger_print(); // save the current log + if (arg_debug) + printf("Copying files in the new home:\n"); + // copy the list of files in the new home directory - // using a new child process without root privileges - pid_t child = fork(); - if (child < 0) - errExit("fork"); - if (child == 0) { - if (arg_debug) - printf("Copying files in the new home:\n"); - - // drop privileges - if (setgroups(0, NULL) < 0) - errExit("setgroups"); - if (setgid(getgid()) < 0) - errExit("setgid/getgid"); - if (setuid(getuid()) < 0) - errExit("setuid/getuid"); - - // copy the list of files in the new home directory - char *dlist = strdup(cfg.home_private_keep); - if (!dlist) - errExit("strdup"); - - char *ptr = strtok(dlist, ","); + char *dlist = strdup(cfg.home_private_keep); + if (!dlist) + errExit("strdup"); + + char *ptr = strtok(dlist, ","); + duplicate(ptr); + while ((ptr = strtok(NULL, ",")) != NULL) duplicate(ptr); - while ((ptr = strtok(NULL, ",")) != NULL) - duplicate(ptr); - - if (!arg_quiet) { - if (size_limit_reached) - fprintf(stderr, "Warning: private-home copy limit of %u MB reached, not all the files were copied\n", - PRIVATE_COPY_LIMIT / (1024 *1024)); - else - printf("Private home: %u files, total size %u bytes\n", file_cnt, size_cnt); - } - fs_logger_print(); // save the current log - free(dlist); -#ifdef HAVE_GCOV - __gcov_flush(); -#endif - _exit(0); - } - // wait for the child to finish - waitpid(child, NULL, 0); + fs_logger_print(); // save the current log + free(dlist); if (arg_debug) printf("Mount-bind %s on top of %s\n", RUN_HOME_DIR, homedir); @@ -640,7 +477,7 @@ void fs_private_home_list(void) { if (mount(RUN_HOME_DIR, homedir, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); - if (u != 0) { + if (uid != 0) { // mask /root if (arg_debug) printf("Mounting a new /root directory\n"); @@ -655,7 +492,7 @@ void fs_private_home_list(void) { errExit("mounting home directory"); } - skel(homedir, u, g); + skel(homedir, uid, gid); if (xflag) copy_xauthority(); if (aflag) diff --git a/src/firejail/main.c b/src/firejail/main.c index ec0c31285..5bfa04cc9 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -1601,7 +1601,6 @@ int main(int argc, char **argv) { // extract private home dirname cfg.home_private_keep = argv[i] + 15; - fs_check_home_list(); arg_private = 1; } else { @@ -1625,7 +1624,6 @@ int main(int argc, char **argv) { fprintf(stderr, "Error: invalid private-etc option\n"); exit(1); } - fs_check_etc_list(); arg_private_etc = 1; } else if (strncmp(argv[i], "--private-bin=", 14) == 0) { diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 0fd45d1ef..693b1dc30 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c @@ -173,7 +173,6 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { #ifdef HAVE_PRIVATE_HOME if (checkcfg(CFG_PRIVATE_HOME)) { cfg.home_private_keep = ptr + 13; - fs_check_home_list(); arg_private = 1; } else @@ -737,7 +736,6 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { exit(1); } cfg.etc_private_keep = ptr + 12; - fs_check_etc_list(); arg_private_etc = 1; return 0; diff --git a/src/firejail/util.c b/src/firejail/util.c index 027f1cd47..c56380ca1 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c @@ -562,7 +562,10 @@ char *expand_home(const char *path, const char* homedir) { return new_name; } - return strdup(path); + char *rv = strdup(path); + if (!rv) + errExit("strdup"); + return rv; } @@ -625,7 +628,7 @@ uid_t pid_get_uid(pid_t pid) { void invalid_filename(const char *fname) { - EUID_ASSERT(); +// EUID_ASSERT(); assert(fname); const char *ptr = fname; -- cgit v1.2.3-54-g00ecf