From edcd62d7523365165e23695d7daabc94f1e9f48d Mon Sep 17 00:00:00 2001 From: netblue30 Date: Wed, 16 Nov 2016 11:10:32 -0500 Subject: fcopy part 1 --- src/fcopy/Makefile.in | 45 +++++++ src/fcopy/main.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/firejail/util.c | 1 + src/fnet/main.c | 6 +- src/fseccomp/main.c | 4 +- 5 files changed, 397 insertions(+), 4 deletions(-) create mode 100644 src/fcopy/Makefile.in create mode 100644 src/fcopy/main.c (limited to 'src') diff --git a/src/fcopy/Makefile.in b/src/fcopy/Makefile.in new file mode 100644 index 000000000..278957a4f --- /dev/null +++ b/src/fcopy/Makefile.in @@ -0,0 +1,45 @@ +all: fcopy + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +sysconfdir=@sysconfdir@ + +VERSION=@PACKAGE_VERSION@ +NAME=@PACKAGE_NAME@ +HAVE_SECCOMP_H=@HAVE_SECCOMP_H@ +HAVE_SECCOMP=@HAVE_SECCOMP@ +HAVE_CHROOT=@HAVE_CHROOT@ +HAVE_BIND=@HAVE_BIND@ +HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@ +HAVE_NETWORK=@HAVE_NETWORK@ +HAVE_USERNS=@HAVE_USERNS@ +HAVE_X11=@HAVE_X11@ +HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@ +HAVE_WHITELIST=@HAVE_WHITELIST@ +HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ +HAVE_APPARMOR=@HAVE_APPARMOR@ +HAVE_OVERLAYFS=@HAVE_OVERLAYFS@ +HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ +EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ +HAVE_GCOV=@HAVE_GCOV@ +EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ + +H_FILE_LIST = $(sort $(wildcard *.[h])) +C_FILE_LIST = $(sort $(wildcard *.c)) +OBJS = $(C_FILE_LIST:.c=.o) +BINOBJS = $(foreach file, $(OBJS), $file) +CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' $(HAVE_GCOV) -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security +LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread + +%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +fcopy: $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) + +clean:; rm -f *.o fcopy *.gcov *.gcda *.gcno + +distclean: clean + rm -fr Makefile + diff --git a/src/fcopy/main.c b/src/fcopy/main.c new file mode 100644 index 000000000..4437b90e5 --- /dev/null +++ b/src/fcopy/main.c @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * 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. +*/ + +#include "../include/common.h" +#include +#include + + +#define COPY_LIMIT (500 * 1024 *1024) +static int size_limit_reached = 0; +static unsigned file_cnt = 0; +static unsigned size_cnt = 0; + +static char *outpath = NULL; +static char *inpath = NULL; + + +// 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); + assert(destname); + mode &= 07777; + + // open source + int src = open(srcname, O_RDONLY); + if (src < 0) { + fprintf(stderr, "Warning: cannot open %s, file not copied\n", srcname); + return; + } + + // open destination + int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, 0755); + if (dst < 0) { + fprintf(stderr, "Warning fcopy: cannot open %s, file not copied\n", destname); + close(src); + return; + } + + // copy + ssize_t len; + static const int BUFLEN = 1024; + unsigned char buf[BUFLEN]; + while ((len = read(src, buf, BUFLEN)) > 0) { + int done = 0; + while (done != len) { + int rv = write(dst, buf + done, len - done); + if (rv == -1) + goto errexit; + done += rv; + } + } + fflush(0); + + if (fchown(dst, uid, gid) == -1) + goto errexit; + if (fchmod(dst, mode) == -1) + goto errexit; + + close(src); + close(dst); + + return; + +errexit: + close(src); + close(dst); + unlink(destname); + fprintf(stderr, "Warning fcopy: cannot copy %s\n", destname); +} + + + +// modified version of the function in firejail/util.c +static void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid) { + assert(fname); + mode &= 07777; + + if (mkdir(fname, mode) == -1 || + chmod(fname, mode) == -1) { + fprintf(stderr, "Error fcopy: failed to create %s directory\n", fname); + errExit("mkdir/chmod"); + } + if (chown(fname, uid, gid)) + fprintf(stderr, "Warning fcopy: failed to change ownership of %s\n", fname); +} + +void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) { + char *rp = realpath(target, NULL); + if (rp) { + if (symlink(rp, linkpath) == -1) + goto errout; + free(rp); + } + else + goto errout; + + return; +errout: + fprintf(stderr, "Warning fcopy: cannot create symbolic link %s\n", target); +} + +static int first = 1; +static int fs_copydir(const char *infname, const struct stat *st, int ftype, struct FTW *sftw) { + (void) st; + (void) sftw; + assert(infname); + assert(*infname != '\0'); + assert(outpath); + assert(*outpath != '\0'); + assert(inpath); + + // check size limit + if (size_limit_reached) + return 0; + + char *outfname; + if (asprintf(&outfname, "%s%s", outpath, infname + strlen(inpath)) == -1) + errExit("asprintf"); + + // don't copy it if we already have the file + struct stat s; + if (stat(outfname, &s) == 0) { + if (first) + first = 0; + else + fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname); + free(outfname); + return 0; + } + + // extract mode and ownership + if (stat(infname, &s) != 0) { + fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname); + free(outfname); + return 0; + } + uid_t uid = s.st_uid; + gid_t gid = s.st_gid; + mode_t mode = s.st_mode; + + // recalculate size + if ((s.st_size + size_cnt) > COPY_LIMIT) { + fprintf(stderr, "Error fcopy: size limit of %dMB reached\n", (COPY_LIMIT / 1024) / 1024); + size_limit_reached = 1; + free(outfname); + return 0; + } + + file_cnt++; + size_cnt += s.st_size; + + if(ftype == FTW_F) { + copy_file(infname, outfname, mode, uid, gid); + } + else if (ftype == FTW_D) { + mkdir_attr(outfname, mode, uid, gid); + } + else if (ftype == FTW_SL) { + copy_link(infname, outfname, mode, uid, gid); + } + + return(0); +} + +static char *check(const char *src) { + struct stat s; + char *rsrc = realpath(src, NULL); + if (!rsrc || stat(rsrc, &s) == -1) { + fprintf(stderr, "Error fcopy: cannot find %s directory\n", src); + exit(1); + } + + // check uid + if (s.st_uid != getuid() || s.st_gid != getgid()) { + fprintf(stderr, "Error fcopy: uid/gid mismatch for %s\n", rsrc); + exit(1); + } + + // dir, link, regular file + if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode) || S_ISLNK(s.st_mode)) { + return rsrc; // normal exit from the function + } + fprintf(stderr, "Error fcopy: invalid directory %s\n", rsrc); + exit(1); +} + +static void duplicate_dir(const char *src, const char *dest, struct stat *s) { + (void) s; + char *rsrc = check(src); + char *rdest = check(dest); + inpath = rsrc; + outpath = rdest; + + // walk + if(nftw(rsrc, fs_copydir, 1, FTW_PHYS) != 0) { + fprintf(stderr, "Error: unable to copy file\n"); + exit(1); + } + + free(rsrc); + free(rdest); +} + +static void duplicate_file(const char *src, const char *dest, struct stat *s) { + char *rsrc = check(src); + char *rdest = check(dest); + uid_t uid = s->st_uid; + gid_t gid = s->st_gid; + mode_t mode = s->st_mode; + + // build destination file name + char *name; + char *ptr = strrchr(rsrc, '/'); + ptr++; + if (asprintf(&name, "%s/%s", rdest, ptr) == -1) + errExit("asprintf"); + + // copy + copy_file(rsrc, name, mode, uid, gid); + + free(name); + free(rsrc); + free(rdest); +} + +static void duplicate_link(const char *src, const char *dest, struct stat *s) { + char *rsrc = check(src); + char *rdest = check(dest); + uid_t uid = s->st_uid; + gid_t gid = s->st_gid; + mode_t mode = s->st_mode; + + // build destination file name + char *name; + char *ptr = strrchr(rsrc, '/'); + ptr++; + if (asprintf(&name, "%s/%s", rdest, ptr) == -1) + errExit("asprintf"); + + // copy + copy_link(rsrc, name, mode, uid, gid); + + free(name); + free(rsrc); + free(rdest); +} + +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"); +} + +int main(int argc, char **argv) { +#if 0 +{ +//system("cat /proc/self/status"); +int i; +for (i = 0; i < argc; i++) + printf("*%s* ", argv[i]); +printf("\n"); +} +#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]; + int len = strlen(src); + if (src[len - 1] == '/') + src[len - 1] = '\0'; + if (strcspn(src, "\\*&!?\"'<>%^(){}[];,") != (size_t)len) { + fprintf(stderr, "Error fcopy: invalid file name %s\n", src); + exit(1); + } + + char *dest = argv[index + 1]; + len = strlen(dest); + if (dest[len - 1] == '/') + dest[len - 1] = '\0'; + if (strcspn(dest, "\\*&!?\"'<>%^(){}[];,~") != (size_t)len) { + fprintf(stderr, "Error fcopy: invalid file name %s\n", dest); + exit(1); + } + + + // the destination should be a directory; remove ending / + 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"); + exit(1); + } + + // copy files + if (lstat(src, &s) == -1) { + fprintf(stderr, "Error fcopy: cannot find source file\n"); + exit(1); + } + + if (S_ISDIR(s.st_mode)) + duplicate_dir(src, dest, &s); + else if (S_ISREG(s.st_mode)) + duplicate_file(src, dest, &s); + else if (S_ISLNK(s.st_mode)) + duplicate_link(src, dest, &s); + else { + fprintf(stderr, "Error fcopy: source file unsupported\n"); + exit(1); + } + + return 0; +} diff --git a/src/firejail/util.c b/src/firejail/util.c index d928c6b42..027f1cd47 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c @@ -206,6 +206,7 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m done += rv; } } + fflush(0); if (fchown(dst, uid, gid) == -1) errExit("fchown"); diff --git a/src/fnet/main.c b/src/fnet/main.c index 4ae9eb6e3..4e7807d07 100644 --- a/src/fnet/main.c +++ b/src/fnet/main.c @@ -42,10 +42,10 @@ for (i = 0; i < argc; i++) printf("\n"); } #endif - if (argc < 2) + if (argc < 2) { + usage(); return 1; - - + } if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { usage(); diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c index 39e72fdf9..2f85a786b 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c @@ -47,8 +47,10 @@ for (i = 0; i < argc; i++) printf("\n"); } #endif - if (argc < 2) + if (argc < 2) { + usage(); return 1; + } if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { usage(); -- cgit v1.2.3-54-g00ecf From 98159c098b6afedfed20eecdc80719dae1f914ff Mon Sep 17 00:00:00 2001 From: netblue30 Date: Wed, 16 Nov 2016 16:40:12 -0500 Subject: fcopy part 2 --- gcov.sh | 28 +++-- 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 +- test/fcopy/cmdline.exp | 10 -- test/fcopy/filecopy.exp | 6 +- test/fcopy/linkcopy.exp | 46 ++------- 11 files changed, 101 insertions(+), 340 deletions(-) (limited to 'src') diff --git a/gcov.sh b/gcov.sh index 6f668d65f..900b7ca41 100755 --- a/gcov.sh +++ b/gcov.sh @@ -1,22 +1,28 @@ #!/bin/bash +gcov_init() { + USER=`whoami` + firejail --help + firemon --help + /usr/lib/firejail/fnet --help + /usr/lib/firejail/fseccomp --help + /usr/lib/firejail/ftee --help + /usr/lib/firejail/fcopy --help + firecfg --help + sudo chown $USER:$USER `find .` +} + generate() { - lcov --capture -d src/firejail -d src/firemon -d src/fseccomp -d src/fnet -d src/ftee -d src/lib -d src/firecfg --output-file gcov-file + lcov --capture -d src/firejail -d src/firemon -d src/fcopy -d src/fseccomp -d src/fnet -d src/ftee -d src/lib -d src/firecfg --output-file gcov-file rm -fr gcov-dir genhtml gcov-file --output-directory gcov-dir } -# init -USER=`whoami` -firejail --help -firemon --help -/usr/lib/firejail/fnet --help -/usr/lib/firejail/fseccomp --help -/usr/lib/firejail/ftee --help -/usr/lib/firejail/fcopy --help -firecfg --help -sudo chown $USER:$USER `find .` +gcov_init generate +echo "press any key to continue, or Ctrl-C to exit" +read text + # running tests make test-root 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; diff --git a/test/fcopy/cmdline.exp b/test/fcopy/cmdline.exp index 95e221321..24bb19351 100755 --- a/test/fcopy/cmdline.exp +++ b/test/fcopy/cmdline.exp @@ -43,14 +43,4 @@ expect { } after 100 -send -- "/usr/lib/firejail/fcopy foo1 foo2\r" -expect { - timeout {puts "TESTING ERROR 6\n";exit} - "cannot find destination directory" -} -after 100 - - - - puts "\nall done\n" diff --git a/test/fcopy/filecopy.exp b/test/fcopy/filecopy.exp index 9927e18fe..d1f0a4424 100755 --- a/test/fcopy/filecopy.exp +++ b/test/fcopy/filecopy.exp @@ -13,7 +13,7 @@ match_max 100000 send -- "rm -fr dest/*\r" after 100 -send -- "/usr/lib/firejail/fcopy src/dircopy.exp dest\r" +send -- "/usr/lib/firejail/fcopy dircopy.exp dest\r" after 100 send -- "find dest\r" @@ -31,7 +31,7 @@ after 100 send -- "ls -al dest\r" expect { timeout {puts "TESTING ERROR 2\n";exit} - "lrwxrwxrwx" + "rwxr-xr-x" } after 100 @@ -45,7 +45,7 @@ expect { send -- "file dest/dircopy.exp\r" expect { timeout {puts "TESTING ERROR 5\n";exit} - "symbolic link" + "ASCII text" } send -- "rm -fr dest/*\r" diff --git a/test/fcopy/linkcopy.exp b/test/fcopy/linkcopy.exp index b87f24a59..9927e18fe 100755 --- a/test/fcopy/linkcopy.exp +++ b/test/fcopy/linkcopy.exp @@ -13,7 +13,7 @@ match_max 100000 send -- "rm -fr dest/*\r" after 100 -send -- "/usr/lib/firejail/fcopy src dest\r" +send -- "/usr/lib/firejail/fcopy src/dircopy.exp dest\r" after 100 send -- "find dest\r" @@ -23,60 +23,28 @@ expect { } expect { timeout {puts "TESTING ERROR 1\n";exit} - "dest/a" -} -expect { - timeout {puts "TESTING ERROR 2\n";exit} - "dest/a/b" -} -expect { - timeout {puts "TESTING ERROR 3\n";exit} - "dest/a/b/file4" -} -expect { - timeout {puts "TESTING ERROR 4\n";exit} - "dest/a/file3" -} -expect { - timeout {puts "TESTING ERROR 5\n";exit} "dest/dircopy.exp" } -expect { - timeout {puts "TESTING ERROR 6\n";exit} - "dest/file2" -} -expect { - timeout {puts "TESTING ERROR 7\n";exit} - "dest/file1" -} after 100 send -- "ls -al dest\r" expect { - timeout {puts "TESTING ERROR 8\n";exit} - "drwx--x--x" -} -expect { - timeout {puts "TESTING ERROR 9\n";exit} - "rwxrwxrwx" -} -expect { - timeout {puts "TESTING ERROR 10\n";exit} - "rw-r--r--" + timeout {puts "TESTING ERROR 2\n";exit} + "lrwxrwxrwx" } after 100 -send -- "diff -q src/a/b/file4 dest/a/b/file4; echo done\r" +send -- "diff -q dircopy.exp dest/dircopy.exp; echo done\r" expect { - timeout {puts "TESTING ERROR 11\n";exit} - "differ" {puts "TESTING ERROR 12\n";exit} + timeout {puts "TESTING ERROR 3\n";exit} + "differ" {puts "TESTING ERROR 4\n";exit} "done" } send -- "file dest/dircopy.exp\r" expect { - timeout {puts "TESTING ERROR 13\n";exit} + timeout {puts "TESTING ERROR 5\n";exit} "symbolic link" } -- cgit v1.2.3-54-g00ecf From cee0a4d375092f5c9e1097ce056dd10435b33e49 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Thu, 17 Nov 2016 08:04:52 -0500 Subject: testing --- src/fcopy/main.c | 19 ++++++++----------- src/firemon/caps.c | 1 - src/firemon/procevent.c | 6 ++---- src/firemon/seccomp.c | 4 +--- src/ftee/main.c | 32 ++++++++++++-------------------- test/utils/firemon-cpu.exp | 1 - test/utils/firemon-interface.exp | 18 ++++++++++++++++++ test/utils/firemon-name.exp | 28 ++++++++++++++++++++++++++++ test/utils/firemon-version.exp | 18 ++++++++++++++++++ test/utils/utils.sh | 9 +++++++++ 10 files changed, 96 insertions(+), 40 deletions(-) create mode 100755 test/utils/firemon-interface.exp create mode 100755 test/utils/firemon-name.exp create mode 100755 test/utils/firemon-version.exp (limited to 'src') diff --git a/src/fcopy/main.c b/src/fcopy/main.c index 82d829bba..ca2643e7d 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c @@ -188,22 +188,19 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str static char *check(const char *src) { struct stat s; char *rsrc = realpath(src, NULL); - if (!rsrc || stat(rsrc, &s) == -1) { - fprintf(stderr, "Error fcopy: cannot find %s directory\n", src); - exit(1); - } + if (!rsrc || stat(rsrc, &s) == -1) + goto errexit; // check uid - if (s.st_uid != getuid() || s.st_gid != getgid()) { - fprintf(stderr, "Error fcopy: uid/gid mismatch for %s\n", rsrc); - exit(1); - } + if (s.st_uid != getuid() || s.st_gid != getgid()) + goto errexit; // dir, link, regular file - if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode) || S_ISLNK(s.st_mode)) { + if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode) || S_ISLNK(s.st_mode)) return rsrc; // normal exit from the function - } - fprintf(stderr, "Error fcopy: invalid directory %s\n", rsrc); + +errexit: + fprintf(stderr, "Error fcopy: invalid file %s\n", src); exit(1); } diff --git a/src/firemon/caps.c b/src/firemon/caps.c index 81877ab87..3f8a139ae 100644 --- a/src/firemon/caps.c +++ b/src/firemon/caps.c @@ -24,7 +24,6 @@ static void print_caps(int pid) { char *file; if (asprintf(&file, "/proc/%d/status", pid) == -1) { errExit("asprintf"); - exit(1); } FILE *fp = fopen(file, "r"); diff --git a/src/firemon/procevent.c b/src/firemon/procevent.c index 1940f4a34..edae21951 100644 --- a/src/firemon/procevent.c +++ b/src/firemon/procevent.c @@ -43,10 +43,8 @@ static int pid_is_firejail(pid_t pid) { // open /proc/self/comm char *file; - if (asprintf(&file, "/proc/%u/comm", pid) == -1) { - perror("asprintf"); - exit(1); - } + if (asprintf(&file, "/proc/%u/comm", pid) == -1) + errExit("asprintf"); FILE *fp = fopen(file, "r"); if (!fp) { diff --git a/src/firemon/seccomp.c b/src/firemon/seccomp.c index abc698bb8..f11c624ea 100644 --- a/src/firemon/seccomp.c +++ b/src/firemon/seccomp.c @@ -22,10 +22,8 @@ #define MAXBUF 4098 static void print_seccomp(int pid) { char *file; - if (asprintf(&file, "/proc/%d/status", pid) == -1) { + if (asprintf(&file, "/proc/%d/status", pid) == -1) errExit("asprintf"); - exit(1); - } FILE *fp = fopen(file, "r"); if (!fp) { diff --git a/src/ftee/main.c b/src/ftee/main.c index e6aa5f567..2b27baa5a 100644 --- a/src/ftee/main.c +++ b/src/ftee/main.c @@ -179,10 +179,6 @@ static int is_link(const char *fname) { return 0; } - - - - static void usage(void) { printf("Usage: ftee filename\n"); } @@ -201,33 +197,25 @@ int main(int argc, char **argv) { // do not accept directories, links, and files with ".." - if (strstr(fname, "..") || is_link(fname) || is_dir(fname)) { - fprintf(stderr, "Error: invalid output file. Links, directories and files with \"..\" are not allowed.\n"); - exit(1); - } + if (strstr(fname, "..") || is_link(fname) || is_dir(fname)) + goto errexit; struct stat s; if (stat(fname, &s) == 0) { // check permissions - if (s.st_uid != getuid() || s.st_gid != getgid()) { - fprintf(stderr, "Error: the output file needs to be owned by the current user.\n"); - exit(1); - } + if (s.st_uid != getuid() || s.st_gid != getgid()) + goto errexit; // check hard links - if (s.st_nlink != 1) { - fprintf(stderr, "Error: no hard links allowed.\n"); - exit(1); - } + if (s.st_nlink != 1) + goto errexit; } // check if we can append to this file /* coverity[toctou] */ FILE *fp = fopen(fname, "a"); - if (!fp) { - fprintf(stderr, "Error: cannot open output file %s\n", fname); - exit(1); - } + if (!fp) + goto errexit; fclose(fp); @@ -248,4 +236,8 @@ int main(int argc, char **argv) { log_close(); return 0; + +errexit: + fprintf(stderr, "Error ftee: invalid output file.\n"); + return 1; } diff --git a/test/utils/firemon-cpu.exp b/test/utils/firemon-cpu.exp index f2ecd4a5c..00156c909 100755 --- a/test/utils/firemon-cpu.exp +++ b/test/utils/firemon-cpu.exp @@ -24,7 +24,6 @@ sleep 1 spawn $env(SHELL) send -- "firemon --cpu\r" -sleep 4 expect { timeout {puts "TESTING ERROR 2\n";exit} "need to be root" {puts "TESTING SKIP: /proc mounted as hidepid\n"; exit} diff --git a/test/utils/firemon-interface.exp b/test/utils/firemon-interface.exp new file mode 100755 index 000000000..edafd1639 --- /dev/null +++ b/test/utils/firemon-interface.exp @@ -0,0 +1,18 @@ +#!/usr/bin/expect -f +# This file is part of Firejail project +# Copyright (C) 2014-2016 Firejail Authors +# License GPL v2 + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firemon --interface\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "you need to be root" +} +after 100 + +puts "\nall done\n" + diff --git a/test/utils/firemon-name.exp b/test/utils/firemon-name.exp new file mode 100755 index 000000000..c5dbfabab --- /dev/null +++ b/test/utils/firemon-name.exp @@ -0,0 +1,28 @@ +#!/usr/bin/expect -f +# This file is part of Firejail project +# Copyright (C) 2014-2016 Firejail Authors +# License GPL v2 + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --name=test\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firemon --cpu --name=test\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "need to be root" {puts "TESTING SKIP: /proc mounted as hidepid\n"; exit} + "Cpus_allowed_list" +} + +after 100 + +puts "\nall done\n" + diff --git a/test/utils/firemon-version.exp b/test/utils/firemon-version.exp new file mode 100755 index 000000000..639c15c29 --- /dev/null +++ b/test/utils/firemon-version.exp @@ -0,0 +1,18 @@ +#!/usr/bin/expect -f +# This file is part of Firejail project +# Copyright (C) 2014-2016 Firejail Authors +# License GPL v2 + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firemon --version\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "firemon version" +} +after 100 + +puts "\nall done\n" + diff --git a/test/utils/utils.sh b/test/utils/utils.sh index bd91110f7..804e5ae0f 100755 --- a/test/utils/utils.sh +++ b/test/utils/utils.sh @@ -100,3 +100,12 @@ echo "TESTING: firemon cpu (test/utils/firemon-cpu.exp)" echo "TESTING: firemon cgroup (test/utils/firemon-cgroup.exp)" ./firemon-cgroup.exp +echo "TESTING: firemon version (test/utils/firemon-version.exp)" +./firemon-version.exp + +echo "TESTING: firemon interface (test/utils/firemon-interface.exp)" +./firemon-interface.exp + +echo "TESTING: firemon name (test/utils/firemon-name.exp)" +./firemon-name.exp + -- cgit v1.2.3-54-g00ecf From 478a290aefdbf64596a1dafe0ad4420afac28200 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Thu, 17 Nov 2016 08:21:09 -0500 Subject: cleanup --- src/firejail/appimage.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c index a658173eb..01a78c324 100644 --- a/src/firejail/appimage.c +++ b/src/firejail/appimage.c @@ -31,10 +31,6 @@ static char *devloop = NULL; // device file static char *mntdir = NULL; // mount point in /tmp directory -const char *appimage_getdir(void) { - return mntdir; -} - void appimage_set(const char *appimage_path) { assert(appimage_path); assert(devloop == NULL); // don't call this twice! -- cgit v1.2.3-54-g00ecf From 4c2ed4eeafcacb380cba143d216811501ad57f33 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Thu, 17 Nov 2016 09:59:15 -0500 Subject: fcopy part 3 --- src/fcopy/main.c | 4 +- src/firejail/fs_etc.c | 109 +++++++++++++++++++------------------------------- src/firejail/util.c | 2 + 3 files changed, 45 insertions(+), 70 deletions(-) (limited to 'src') diff --git a/src/fcopy/main.c b/src/fcopy/main.c index ca2643e7d..56d297c9a 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c @@ -272,7 +272,7 @@ static void usage(void) { } int main(int argc, char **argv) { -#if 0 +//#if 0 { //system("cat /proc/self/status"); int i; @@ -280,7 +280,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/fs_etc.c b/src/firejail/fs_etc.c index 6a70d482c..7d4ffa938 100644 --- a/src/firejail/fs_etc.c +++ b/src/firejail/fs_etc.c @@ -21,18 +21,14 @@ #include #include #include -#include #include // return 0 if file not found, 1 if found -static int check_dir_or_file(const char *name) { - assert(name); - invalid_filename(name); +static int check_dir_or_file(const char *fname) { + assert(fname); + invalid_filename(fname); struct stat s; - char *fname; - if (asprintf(&fname, "/etc/%s", name) == -1) - errExit("asprintf"); if (arg_debug) printf("Checking %s\n", fname); if (stat(fname, &s) == -1) { @@ -46,16 +42,8 @@ static int check_dir_or_file(const char *name) { goto errexit; // dir or regular file - if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode)) { - free(fname); - return 1; - } - - if (!is_link(fname)) { - free(fname); - return 1; - } - + if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode) || !is_link(fname)) + return 1; // normal exit errexit: fprintf(stderr, "Error: invalid file type, %s.\n", fname); @@ -63,30 +51,32 @@ errexit: } static void duplicate(char *fname) { - // copy the file - if (arg_debug) - printf("running: %s -a --parents /etc/%s %s\n", RUN_CP_COMMAND, fname, RUN_MNT_DIR); - - pid_t child = fork(); - if (child < 0) - errExit("fork"); - if (child == 0) { - char *f; - if (asprintf(&f, "/etc/%s", fname) == -1) + char *src; + if (asprintf(&src, "/etc/%s", fname) == -1) + errExit("asprintf"); + if (check_dir_or_file(src) == 0) { + if (!arg_quiet) + fprintf(stderr, "Warning: skipping %s for private bin\n", fname); + free(src); + return; + } + + + struct stat s; + if (stat(src, &s) == 0 && S_ISDIR(s.st_mode)) { + // create the directory in RUN_ETC_DIR + char *dirname; + if (asprintf(&dirname, "%s/%s", RUN_ETC_DIR, fname) == -1) errExit("asprintf"); - clearenv(); - execlp(RUN_CP_COMMAND, RUN_CP_COMMAND, "-a", "--parents", f, RUN_MNT_DIR, NULL); - perror("execlp"); - _exit(1); + create_empty_dir_as_root(dirname, s.st_mode); + sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, src, dirname); + free(dirname); } - // wait for the child to finish - waitpid(child, NULL, 0); + else + sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, src, RUN_ETC_DIR); - char *name; - if (asprintf(&name, "/etc/%s", fname) == -1) - errExit("asprintf"); - fs_logger2("clone", name); - free(name); + fs_logger2("clone", src); + free(src); } @@ -110,39 +100,22 @@ void fs_private_etc_list(void) { // copy the list of files in the new etc directory // using a new child process with root privileges if (*private_list != '\0') { - pid_t child = fork(); - if (child < 0) - errExit("fork"); - if (child == 0) { - if (arg_debug) - printf("Copying files in the new etc directory:\n"); + if (arg_debug) + printf("Copying files in the new etc directory:\n"); + + // copy the list of files in the new home directory + char *dlist = strdup(private_list); + if (!dlist) + errExit("strdup"); - // elevate privileges - files in the new /etc 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"); - + + char *ptr = strtok(dlist, ","); + duplicate(ptr); - char *ptr = strtok(dlist, ","); + while ((ptr = strtok(NULL, ",")) != NULL) duplicate(ptr); - - while ((ptr = strtok(NULL, ",")) != NULL) - duplicate(ptr); - free(dlist); - fs_logger_print(); -#ifdef HAVE_GCOV - __gcov_flush(); -#endif - _exit(0); - } - // wait for the child to finish - waitpid(child, NULL, 0); + free(dlist); + fs_logger_print(); } if (arg_debug) diff --git a/src/firejail/util.c b/src/firejail/util.c index c56380ca1..03f52fabb 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c @@ -694,6 +694,7 @@ void flush_stdin(void) { void create_empty_dir_as_root(const char *dir, mode_t mode) { assert(dir); + mode &= 07777; struct stat s; if (stat(dir, &s)) { @@ -709,6 +710,7 @@ void create_empty_dir_as_root(const char *dir, mode_t mode) { void create_empty_file_as_root(const char *fname, mode_t mode) { assert(fname); + mode &= 07777; struct stat s; if (stat(fname, &s)) { -- cgit v1.2.3-54-g00ecf From 94ad4edd5e41a26161fdf0c44f8a0dea77e3d120 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Thu, 17 Nov 2016 13:12:15 -0500 Subject: testing appimage --- src/firejail/appimage.c | 23 ++++++++++++++--------- test/appimage/appimage-v1.exp | 2 +- test/appimage/appimage.sh | 4 +++- test/appimage/filename.exp | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 11 deletions(-) create mode 100755 test/appimage/filename.exp (limited to 'src') diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c index 01a78c324..6a9ca1679 100644 --- a/src/firejail/appimage.c +++ b/src/firejail/appimage.c @@ -31,34 +31,39 @@ static char *devloop = NULL; // device file static char *mntdir = NULL; // mount point in /tmp directory -void appimage_set(const char *appimage_path) { - assert(appimage_path); +void appimage_set(const char *appimage) { + assert(appimage); assert(devloop == NULL); // don't call this twice! EUID_ASSERT(); #ifdef LOOP_CTL_GET_FREE // test for older kernels; this definition is found in /usr/include/linux/loop.h - // check appimage_path - if (access(appimage_path, R_OK) == -1) { + // check appimage file + invalid_filename(appimage); + if (access(appimage, R_OK) == -1) { fprintf(stderr, "Error: cannot access AppImage file\n"); exit(1); } // get appimage type and ELF size // a value of 0 means we are dealing with a type1 appimage - long unsigned int size = appimage2_size(appimage_path); + long unsigned int size = appimage2_size(appimage); if (arg_debug) printf("AppImage ELF size %lu\n", size); - // open as user to prevent race condition - int ffd = open(appimage_path, O_RDONLY|O_CLOEXEC); + // open appimage file + int ffd = open(appimage, O_RDONLY|O_CLOEXEC); if (ffd == -1) { - fprintf(stderr, "Error: /dev/loop-control interface is not supported by your kernel\n"); + fprintf(stderr, "Error: cannot open AppImage file\n"); exit(1); } // find or allocate a free loop device to use EUID_ROOT(); int cfd = open("/dev/loop-control", O_RDWR); + if (cfd == -1) { + fprintf(stderr, "Error: /dev/loop-control interface is not supported by your kernel\n"); + exit(1); + } int devnr = ioctl(cfd, LOOP_CTL_GET_FREE); if (devnr == -1) { fprintf(stderr, "Error: cannot allocate a new loopback device\n"); @@ -113,7 +118,7 @@ void appimage_set(const char *appimage_path) { EUID_USER(); // set environment - if (appimage_path && setenv("APPIMAGE", appimage_path, 1) < 0) + if (appimage && setenv("APPIMAGE", appimage, 1) < 0) errExit("setenv"); if (mntdir && setenv("APPDIR", mntdir, 1) < 0) errExit("setenv"); diff --git a/test/appimage/appimage-v1.exp b/test/appimage/appimage-v1.exp index 503da2b9b..f1c1c10f5 100755 --- a/test/appimage/appimage-v1.exp +++ b/test/appimage/appimage-v1.exp @@ -7,7 +7,7 @@ set timeout 10 spawn $env(SHELL) match_max 100000 -send -- "firejail --name=appimage-test --appimage Leafpad-0.8.17-x86_64.AppImage\r" +send -- "firejail --name=appimage-test --debug --appimage Leafpad-0.8.17-x86_64.AppImage\r" expect { timeout {puts "TESTING ERROR 1\n";exit} "Child process initialized" diff --git a/test/appimage/appimage.sh b/test/appimage/appimage.sh index 6a73d0a7e..db221ec8a 100755 --- a/test/appimage/appimage.sh +++ b/test/appimage/appimage.sh @@ -10,5 +10,7 @@ echo "TESTING: AppImage v1 (test/appimage/appimage-v1.exp)" ./appimage-v1.exp echo "TESTING: AppImage v2 (test/appimage/appimage-v2.exp)" -./appimage-v1.exp +./appimage-v2.exp +echo "TESTING: AppImage file name (test/appimage/filename.exp)"; +./filename.exp \ No newline at end of file diff --git a/test/appimage/filename.exp b/test/appimage/filename.exp new file mode 100755 index 000000000..ce8d70464 --- /dev/null +++ b/test/appimage/filename.exp @@ -0,0 +1,35 @@ +#!/usr/bin/expect -f +# This file is part of Firejail project +# Copyright (C) 2014-2016 Firejail Authors +# License GPL v2 + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --appimage \"bla;bla\"\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "is an invalid filename" +} +after 100 + +send -- "firejail --appimage /etc/shadow\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "cannot access" +} +after 100 + +send -- "firejail --appimage appimage.sh\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Error mounting appimage" +} +after 100 + + + + +puts "\nall done\n" + -- cgit v1.2.3-54-g00ecf 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 + test/environment/dns.exp | 26 ++++++- test/fs/invalid_filename.exp | 15 ++++ test/fs/private-etc.exp | 34 ++++++++- test/fs/private-home.exp | 62 +++++++++++++++- 15 files changed, 211 insertions(+), 227 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 } } diff --git a/test/environment/dns.exp b/test/environment/dns.exp index 6ffb124cf..a6a7171eb 100755 --- a/test/environment/dns.exp +++ b/test/environment/dns.exp @@ -22,9 +22,33 @@ expect { timeout {puts "TESTING ERROR 1.2\n";exit} "53" } - after 100 send -- "rm index.html\r" after 100 +send -- "exit\r" +sleep 1 + +send -- "firejail --dns=8.8.4.4 --dns=8.8.8.8 --dns=4.2.2.1\r" +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "cat /etc/resolv.conf\r" +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "nameserver 8.8.4.4" +} +expect { + timeout {puts "TESTING ERROR 2.3\n";exit} + "nameserver 8.8.8.8" +} +expect { + timeout {puts "TESTING ERROR 2.4\n";exit} + "nameserver 4.2.2.1" +} +after 100 + puts "\nall done\n" diff --git a/test/fs/invalid_filename.exp b/test/fs/invalid_filename.exp index 1acc85491..a6efc24b6 100755 --- a/test/fs/invalid_filename.exp +++ b/test/fs/invalid_filename.exp @@ -109,6 +109,21 @@ expect { } after 100 +send -- "firejail --debug-check-filename --noprofile --private-home=\"bla&&bla\"\r" +expect { + timeout {puts "TESTING ERROR 8.1\n";exit} + "Checking filename bla&&bla" +} +expect { + timeout {puts "TESTING ERROR 8.2\n";exit} + "Error:" +} +expect { + timeout {puts "TESTING ERROR 8.3\n";exit} + "is an invalid filename" +} +after 100 + send -- "firejail --debug-check-filename --noprofile --private-etc=\"bla&&bla\"\r" expect { timeout {puts "TESTING ERROR 9.1\n";exit} diff --git a/test/fs/private-etc.exp b/test/fs/private-etc.exp index e692f7382..36b5d247c 100755 --- a/test/fs/private-etc.exp +++ b/test/fs/private-etc.exp @@ -33,12 +33,40 @@ expect { "resolv.conf" } -send -- "ls -al /etc; echo done\r" + +send -- "file /etc/shadow\r" expect { timeout {puts "TESTING ERROR 7\n";exit} - "shadow" {puts "TESTING ERROR 8\n";exit} - "done" + "No such file or directory" +} +after 100 +send -- "exit\r" +sleep 1 + +send -- "firejail --private-etc=shadow\r" +expect { + timeout {puts "TESTING ERROR 8\n";exit} + "invalid file type" +} +after 100 + +send -- "firejail --private-etc=\"bla;bla\"\r" +expect { + timeout {puts "TESTING ERROR 9\n";exit} + "is an invalid filename" } +after 100 + +send -- "firejail --private-etc=../bin/ls\r" +expect { + timeout {puts "TESTING ERROR 10\n";exit} + "is an invalid filename" +} +after 100 + + + + after 100 puts "\nall done\n" diff --git a/test/fs/private-home.exp b/test/fs/private-home.exp index de5a88dea..3840d1cb8 100755 --- a/test/fs/private-home.exp +++ b/test/fs/private-home.exp @@ -9,11 +9,19 @@ match_max 100000 # create some test files in user home directory send -- "touch ~/_firejail_test_file1\r" +after 100 send -- "touch ~/_firejail_test_file2\r" +after 100 send -- "mkdir ~/_firejail_test_dir1\r" +after 100 send -- "mkdir ~/_firejail_test_dir1/_firejail_test_dir2\r" +after 100 send -- "touch ~/_firejail_test_dir1/_firejail_test_dir2/_firejail_test_file3\r" after 100 +send -- "ln -s /etc ~/_firejail_test_link1\r" +after 100 +send -- "ln -s ~/_firejail_test_dir1 ~/_firejail_test_link2\r" +after 100 send -- "firejail --private-home=_firejail_test_file1,_firejail_test_file2,_firejail_test_dir1\r" expect { @@ -37,8 +45,58 @@ expect { } after 100 -send -- "rm -f ~/_firejail_test_file*\r" -send -- "rm -fr ~/_firejail_test_dir*\r" +send -- "exit\r" +sleep 1 + +send -- "firejail --private-home=\"bla;bla\"\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "is an invalid filename" +} +after 100 + +send -- "firejail --private-home=/etc/shadow\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "invalid file" +} +after 100 + +send -- "firejail --private-home=/etc/passwd\r" +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "invalid file" +} +after 100 + +send -- "firejail --private-home=../../etc/passwd\r" +expect { + timeout {puts "TESTING ERROR 8\n";exit} + "invalid file" +} +after 100 + +send -- "firejail --private-home=_firejail_test_link1\r" +expect { + timeout {puts "TESTING ERROR 9\n";exit} + "to file or directory not owned by the user" +} +after 100 + +send -- "firejail --private-home=_firejail_test_link2\r" +expect { + timeout {puts "TESTING ERROR 10\n";exit} + "Child process initialized" +} +after 100 +send -- "file file ~/_firejail_test_link2\r" +expect { + timeout {puts "TESTING ERROR 11\n";exit} + "broken symbolic link" +} +send -- "exit\r" + +send -- "rm -f ~/_firejail_test*\r" after 100 puts "\nall done\n" -- cgit v1.2.3-54-g00ecf From 4840712323d034e7452f63d6f747cc6a78d364c0 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Fri, 18 Nov 2016 10:09:26 -0500 Subject: cleanup --- README.md | 4 ++++ RELNOTES | 3 +++ src/fcopy/main.c | 3 +++ src/firejail/fs_home.c | 1 - 4 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/README.md b/README.md index ad90639e2..b29ad476e 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,10 @@ Use this issue to request new profiles: https://github.com/netblue30/firejail/is # Current development version: 0.9.45 ````` +````` +## AppImage type 2 support +````` + ````` ## New Profiles xiphos, Tor Browser Bundle, display (imagemagik), Wire, mumble, zoom,Guayadeque diff --git a/RELNOTES b/RELNOTES index e726674ec..38da86b6e 100644 --- a/RELNOTES +++ b/RELNOTES @@ -5,7 +5,10 @@ firejail (0.9.45) baseline; urgency=low * security: invalid environment exploit found by Martin Carpenter * security: split most of networking code in a separate executable * security: split seccomp filter code configuration in a separate executable + * security: split file copying in private option in a separate executable * feature: allow root user access to /dev/shm (--noblacklist=/dev/shm) + * feature: AppImage type 2 support + * feature: test coverage (gcov) support * new profiles: xiphos, Tor Browser Bundle, display (imagemagik), Wire, * new profiles: mumble, zoom, Guayadeque * bugfixes diff --git a/src/fcopy/main.c b/src/fcopy/main.c index e3a04a515..b1e2813db 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c @@ -102,6 +102,9 @@ static void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid) { } void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) { + (void) mode; + (void) uid; + (void) gid; char *rp = realpath(target, NULL); if (rp) { if (symlink(rp, linkpath) == -1) diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 1612da5d3..1f8da398e 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c @@ -406,7 +406,6 @@ static char *check_dir_or_file(const char *name) { static void duplicate(char *name) { char *fname = check_dir_or_file(name); - char *dest = RUN_HOME_DIR; if (arg_debug) printf("Private home: duplicating %s\n", fname); -- cgit v1.2.3-54-g00ecf