From 21f163ba9d1ea7247283d828774b2447059b294a Mon Sep 17 00:00:00 2001 From: netblue30 Date: Fri, 27 Nov 2015 07:48:28 -0500 Subject: implemented filesystem log --- RELNOTES | 1 + src/firejail/firejail.h | 9 +++++++++ src/firejail/fs.c | 24 ++++++++++++++++++++++++ src/firejail/fs_bin.c | 6 ++++++ src/firejail/fs_dev.c | 15 +++++++++++++++ src/firejail/fs_etc.c | 6 +++++- src/firejail/fs_home.c | 21 ++++++++++++++++++++- src/firejail/fs_hostname.c | 5 ++++- src/firejail/fs_trace.c | 2 ++ src/firejail/fs_var.c | 19 ++++++++++++++++++- src/firejail/fs_whitelist.c | 12 +++++++++++- src/firejail/main.c | 10 +++++++++- src/firejail/pulseaudio.c | 1 + src/firejail/restrict_users.c | 39 +++++---------------------------------- src/firejail/sandbox.c | 5 ++++- src/firejail/usage.c | 6 +++++- src/firejail/util.c | 6 +++++- src/man/firejail.txt | 29 +++++++++++++++++++++++++++++ todo | 8 ++++++++ 19 files changed, 181 insertions(+), 43 deletions(-) diff --git a/RELNOTES b/RELNOTES index 1b2c28726..fd004fb0e 100644 --- a/RELNOTES +++ b/RELNOTES @@ -10,6 +10,7 @@ firejail (0.9.35) baseline; urgency=low * added automated feature testing framework * alow default gateway configuration for --interface option * --debug enhancements + * filesystem log * bugfixes -- netblue30 ongoing development diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index e4e6f4fa4..b50b4d19e 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -56,6 +56,7 @@ #define RUN_UTMP_FILE "/run/firejail/mnt/utmp" #define RUN_PASSWD_FILE "/run/firejail/mnt/passwd" #define RUN_GROUP_FILE "/run/firejail/mnt/group" +#define RUN_FSLOGGER_FILE "/run/firejail/mnt/fslogger" // profiles #define DEFAULT_USER_PROFILE "generic" @@ -479,6 +480,14 @@ void protocol_filter_load(const char *fname); // restrict_users.c void restrict_users(void); +// fs_logger.c +void fs_logger(const char *msg); +void fs_logger2(const char *msg1, const char *msg2); +void fs_logger3(const char *msg1, const char *msg2, const char *msg3); +void fs_logger_print(void); +void fs_logger_change_owner(void); +void fs_logger_print_log_name(const char *name); +void fs_logger_print_log(pid_t pid); #endif diff --git a/src/firejail/fs.c b/src/firejail/fs.c index e442bc705..6572f657b 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c @@ -213,6 +213,7 @@ static void disable_file(OPERATION op, const char *filename) { errExit("disable file"); } last_disable = SUCCESSFUL; + fs_logger2("blacklist", fname); } } else if (op == MOUNT_READONLY) { @@ -232,6 +233,7 @@ static void disable_file(OPERATION op, const char *filename) { if (chown(fname, s.st_uid, s.st_gid) == -1) errExit("mounting tmpfs chmod"); last_disable = SUCCESSFUL; + fs_logger2("mount tmpfs on", fname); } else printf("Warning: %s is not a directory; cannot mount a tmpfs on top of it.\n", fname); @@ -427,6 +429,7 @@ void fs_rdonly(const char *dir) { // mount --bind -o remount,ro /bin if (mount(NULL, dir, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_REC, NULL) < 0) errExit("mount read-only"); + fs_logger2("read-only", dir); } } void fs_rdonly_noexit(const char *dir) { @@ -444,6 +447,8 @@ void fs_rdonly_noexit(const char *dir) { merr = 1; if (merr) fprintf(stderr, "Warning: cannot mount %s read-only\n", dir); + else + fs_logger2("read-only", dir); } } @@ -455,6 +460,7 @@ void fs_proc_sys_dev_boot(void) { printf("Remounting /proc and /proc/sys filesystems\n"); if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) errExit("mounting /proc"); + fs_logger("remount /proc"); // remount /proc/sys readonly if (mount("/proc/sys", "/proc/sys", NULL, MS_BIND | MS_REC, NULL) < 0) @@ -462,6 +468,7 @@ void fs_proc_sys_dev_boot(void) { if (mount(NULL, "/proc/sys", NULL, MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, NULL) < 0) errExit("mounting /proc/sys"); + fs_logger("read-only /proc/sys"); /* Mount a version of /sys that describes the network namespace */ @@ -471,28 +478,45 @@ void fs_proc_sys_dev_boot(void) { fprintf(stderr, "Warning: failed to unmount /sys\n"); if (mount("sysfs", "/sys", "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REC, NULL) < 0) fprintf(stderr, "Warning: failed to mount /sys\n"); + else + fs_logger("remount /sys"); + if (arg_debug) printf("Disable /sys/firmware directory\n"); if (mount("tmpfs", "/sys/firmware", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) fprintf(stderr, "Warning: cannot disable /sys/firmware directory\n"); + else + fs_logger("mount tmpfs on /sys/firmware"); + if (arg_debug) printf("Disable /sys/hypervisor directory\n"); if (mount("tmpfs", "/sys/hypervisor", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) fprintf(stderr, "Warning: cannot disable /sys/hypervisor directory\n"); + else + fs_logger("mount tmpfs on /sys/hypervisor"); + if (arg_debug) printf("Disable /sys/fs directory\n"); if (mount("tmpfs", "/sys/fs", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) fprintf(stderr, "Warning: cannot disable /sys/fs directory\n"); + else + fs_logger("mount tmpfs on /sys/fs"); + if (arg_debug) printf("Disable /sys/module directory\n"); if (mount("tmpfs", "/sys/module", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) fprintf(stderr, "Warning: cannot disable /sys/module directory\n"); + else + fs_logger("mount tmpfs on /sys/module"); + if (arg_debug) printf("Disable /sys/power directory\n"); if (mount("tmpfs", "/sys/power", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) fprintf(stderr, "Warning: cannot disable /sys/power directory\n"); + else + fs_logger("mount tmpfs on /sys/power"); diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c index 946c75d30..a990d9d79 100644 --- a/src/firejail/fs_bin.c +++ b/src/firejail/fs_bin.c @@ -143,6 +143,7 @@ static void duplicate(char *fname) { printf("%s\n", cmd); if (system(cmd)) errExit("system cp -a"); + fs_logger2("clone", fname); free(cmd); free(actual_path); } @@ -176,8 +177,10 @@ void fs_private_bin_list(void) { if (chmod(RUN_BIN_DIR, 0755) < 0) errExit("chmod"); + // 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"); @@ -196,12 +199,14 @@ void fs_private_bin_list(void) { if (!dlist) errExit("strdup"); + char *ptr = strtok(dlist, ","); duplicate(ptr); while ((ptr = strtok(NULL, ",")) != NULL) duplicate(ptr); free(dlist); + fs_logger_print(); exit(0); } // wait for the child to finish @@ -214,6 +219,7 @@ void fs_private_bin_list(void) { printf("Mount-bind %s on top of %s\n", RUN_BIN_DIR, paths[i]); if (mount(RUN_BIN_DIR, paths[i], NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); + fs_logger2("mount", paths[i]); i++; } } diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c index 86e0918e1..c0cb49db7 100644 --- a/src/firejail/fs_dev.c +++ b/src/firejail/fs_dev.c @@ -107,6 +107,7 @@ void fs_private_dev(void){ // mount tmpfs on top of /dev if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) errExit("mounting /dev"); + fs_logger("mount tmpfs on /dev"); // bring back /dev/log if (have_devlog) { @@ -116,6 +117,7 @@ void fs_private_dev(void){ fclose(fp); if (mount(RUN_DEVLOG_FILE, "/dev/log", NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mounting /dev/log"); + fs_logger("clone /dev/log"); } } @@ -131,6 +133,7 @@ void fs_private_dev(void){ errExit("chmod"); if (mount(RUN_DRI_DIR, "/dev/dri", NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mounting /dev/dri"); + fs_logger("clone /dev/dri"); } // create /dev/shm @@ -143,14 +146,21 @@ void fs_private_dev(void){ errExit("chown"); if (chmod("/dev/shm", 0777) < 0) errExit("chmod"); + fs_logger("mkdir /dev/shm"); // create devices create_char_dev("/dev/zero", 0666, 1, 5); // mknod -m 666 /dev/zero c 1 5 + fs_logger("mknod /dev/zero"); create_char_dev("/dev/null", 0666, 1, 3); // mknod -m 666 /dev/null c 1 3 + fs_logger("mknod /dev/null"); create_char_dev("/dev/full", 0666, 1, 7); // mknod -m 666 /dev/full c 1 7 + fs_logger("mknod /dev/full"); create_char_dev("/dev/random", 0666, 1, 8); // Mknod -m 666 /dev/random c 1 8 + fs_logger("mknod /dev/random"); create_char_dev("/dev/urandom", 0666, 1, 9); // mknod -m 666 /dev/urandom c 1 9 + fs_logger("mknod /dev/urandom"); create_char_dev("/dev/tty", 0666, 5, 0); // mknod -m 666 /dev/tty c 5 0 + fs_logger("mknod /dev/tty"); #if 0 create_dev("/dev/tty0", "mknod -m 666 /dev/tty0 c 4 0"); create_dev("/dev/console", "mknod -m 622 /dev/console c 5 1"); @@ -164,11 +174,14 @@ void fs_private_dev(void){ errExit("chown"); if (chmod("/dev/pts", 0755) < 0) errExit("chmod"); + fs_logger("mkdir /dev/pts"); create_char_dev("/dev/pts/ptmx", 0666, 5, 2); //"mknod -m 666 /dev/pts/ptmx c 5 2"); + fs_logger("mknod /dev/pts/ptmx"); create_link("/dev/pts/ptmx", "/dev/ptmx"); // mount -vt devpts -o newinstance -o ptmxmode=0666 devpts //dev/pts if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, "newinstance,ptmxmode=0666") < 0) errExit("mounting /dev/pts"); + fs_logger("mount devpts"); #if 0 // stdin, stdout, stderr @@ -190,6 +203,7 @@ void fs_dev_shm(void) { printf("Mounting tmpfs on /dev/shm\n"); if (mount("tmpfs", "/dev/shm", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) errExit("mounting /dev/shm"); + fs_logger("mount tmpfs on /dev/shm"); } else { char *lnk = realpath("/dev/shm", NULL); @@ -207,6 +221,7 @@ void fs_dev_shm(void) { printf("Mounting tmpfs on %s on behalf of /dev/shm\n", lnk); if (mount("tmpfs", lnk, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) errExit("mounting /var/tmp"); + fs_logger3("mount tmpfs on", lnk, "on behalf of /dev/shm"); free(lnk); } else { diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c index 28e337abc..df0e92203 100644 --- a/src/firejail/fs_etc.c +++ b/src/firejail/fs_etc.c @@ -83,6 +83,7 @@ static void duplicate(char *fname) { if (system(cmd)) errExit("system cp -a --parents"); free(cmd); + fs_logger2("clone", fname); } @@ -108,6 +109,7 @@ void fs_private_etc_list(void) { // 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"); @@ -126,12 +128,14 @@ void fs_private_etc_list(void) { if (!dlist) errExit("strdup"); + char *ptr = strtok(dlist, ","); duplicate(ptr); while ((ptr = strtok(NULL, ",")) != NULL) duplicate(ptr); free(dlist); + fs_logger_print(); exit(0); } // wait for the child to finish @@ -141,6 +145,6 @@ void fs_private_etc_list(void) { printf("Mount-bind %s on top of /etc\n", RUN_ETC_DIR); if (mount(RUN_ETC_DIR, "/etc", NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); - + fs_logger("mount /etc"); } diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index ca9f7b472..f9e8d62f9 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c @@ -44,6 +44,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { if (copy_file("/etc/skel/.zshrc", fname) == 0) { if (chown(fname, u, g) == -1) errExit("chown"); + fs_logger("clone /etc/skel/.zshrc"); } } else { // @@ -55,6 +56,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { errExit("chown"); if (chmod(fname, S_IRUSR | S_IWUSR) < 0) errExit("chown"); + fs_logger2("touch", fname); } } free(fname); @@ -72,6 +74,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { if (copy_file("/etc/skel/.cshrc", fname) == 0) { if (chown(fname, u, g) == -1) errExit("chown"); + fs_logger("clone /etc/skel/.cshrc"); } } else { // @@ -84,6 +87,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { errExit("chown"); if (chmod(fname, S_IRUSR | S_IWUSR) < 0) errExit("chown"); + fs_logger2("touch", fname); } } free(fname); @@ -102,6 +106,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { /* coverity[toctou] */ if (chown(fname, u, g) == -1) errExit("chown"); + fs_logger("clone /etc/skel/.bashrc"); } } free(fname); @@ -139,6 +144,7 @@ static void copy_xauthority(void) { int rv = copy_file(src, dest); if (rv) fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n"); + fs_logger2("clone", dest); // set permissions and ownership if (chown(dest, getuid(), getgid()) < 0) @@ -177,6 +183,7 @@ void fs_private_homedir(void) { printf("Mount-bind %s on top of %s\n", private_homedir, homedir); if (mount(private_homedir, homedir, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); + fs_logger3("mount-bind", private_homedir, cfg.homedir); // preserve mode and ownership // if (chown(homedir, s.st_uid, s.st_gid) == -1) // errExit("mount-bind chown"); @@ -189,6 +196,7 @@ void fs_private_homedir(void) { printf("Mounting a new /root directory\n"); if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=700,gid=0") < 0) errExit("mounting home directory"); + fs_logger("mount tmpfs on /root"); } else { // mask /home @@ -196,6 +204,7 @@ void fs_private_homedir(void) { printf("Mounting a new /home directory\n"); if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting home directory"); + fs_logger("mount tmpfs on /home"); } @@ -222,12 +231,14 @@ void fs_private(void) { printf("Mounting a new /home directory\n"); if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting home directory"); + fs_logger("mount tmpfs on /home"); // mask /root if (arg_debug) printf("Mounting a new /root directory\n"); if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=700,gid=0") < 0) errExit("mounting home directory"); + fs_logger("mount tmpfs on /root"); if (u != 0) { // create /home/user @@ -241,6 +252,7 @@ void fs_private(void) { } if (chown(homedir, u, g) < 0) errExit("chown"); + fs_logger2("mkdir", homedir); } skel(homedir, u, g); @@ -379,6 +391,7 @@ static void duplicate(char *name) { printf("%s\n", cmd); if (system(cmd)) errExit("system cp -a --parents"); + fs_logger2("clone", fname); free(cmd); free(fname); } @@ -415,9 +428,11 @@ void fs_private_home_list(void) { errExit("chown"); if (chmod(RUN_HOME_DIR, 0755) < 0) errExit("chmod"); + // copy the list of files in the new home 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"); @@ -437,13 +452,14 @@ void fs_private_home_list(void) { char *dlist = strdup(cfg.home_private_keep); if (!dlist) errExit("strdup"); - + char *ptr = strtok(dlist, ","); duplicate(ptr); while ((ptr = strtok(NULL, ",")) != NULL) duplicate(ptr); free(dlist); + fs_logger_print(); exit(0); } // wait for the child to finish @@ -458,6 +474,7 @@ void fs_private_home_list(void) { printf("Mount-bind %s on top of %s\n", newhome, homedir); if (mount(newhome, homedir, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); + fs_logger2("mount", homedir); // preserve mode and ownership // if (chown(homedir, s.st_uid, s.st_gid) == -1) // errExit("mount-bind chown"); @@ -470,6 +487,7 @@ void fs_private_home_list(void) { printf("Mounting a new /root directory\n"); if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=700,gid=0") < 0) errExit("mounting home directory"); + fs_logger("mount tmpfs on /root"); } else { // mask /home @@ -477,6 +495,7 @@ void fs_private_home_list(void) { printf("Mounting a new /home directory\n"); if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting home directory"); + fs_logger("mount tmpfs on /home"); } skel(homedir, u, g); diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c index eb3861d1b..860d0cc14 100644 --- a/src/firejail/fs_hostname.c +++ b/src/firejail/fs_hostname.c @@ -51,6 +51,7 @@ void fs_hostname(const char *hostname) { // bind-mount the file on top of /etc/hostname if (mount(RUN_HOSTNAME_FILE, "/etc/hostname", NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind /etc/hostname"); + fs_logger("create /etc/hostname"); } // create a new /etc/hosts @@ -98,13 +99,14 @@ void fs_hostname(const char *hostname) { // bind-mount the file on top of /etc/hostname if (mount(RUN_HOSTS_FILE, "/etc/hosts", NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind /etc/hosts"); + fs_logger("create /etc/hosts"); } } void fs_resolvconf(void) { if (cfg.dns1 == 0) return; - + struct stat s; fs_build_mnt_dir(); @@ -135,6 +137,7 @@ void fs_resolvconf(void) { // bind-mount the file on top of /etc/hostname if (mount(RUN_RESOLVCONF_FILE, "/etc/resolv.conf", NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind /etc/resolv.conf"); + fs_logger("create /etc/resolv.conf"); } else { fprintf(stderr, "Error: cannot set DNS servers, /etc/resolv.conf file is missing\n"); diff --git a/src/firejail/fs_trace.c b/src/firejail/fs_trace.c index f4f5d3e81..92e4daed2 100644 --- a/src/firejail/fs_trace.c +++ b/src/firejail/fs_trace.c @@ -42,6 +42,7 @@ void fs_trace_preload(void) { errExit("chown"); if (chmod("/etc/ld.so.preload", S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH ) < 0) errExit("chmod"); + fs_logger("touch /etc/ls.so.preload"); } } @@ -68,6 +69,7 @@ void fs_trace(void) { printf("Mount the new ld.so.preload file\n"); if (mount(RUN_LDPRELOAD_FILE, "/etc/ld.so.preload", NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind ls.so.preload"); + fs_logger("create /etc/ls.so.preload"); } diff --git a/src/firejail/fs_var.c b/src/firejail/fs_var.c index c6f989266..a53c22093 100644 --- a/src/firejail/fs_var.c +++ b/src/firejail/fs_var.c @@ -102,6 +102,7 @@ static void build_dirs(void) { errExit("mkdir"); if (chown(ptr->name, ptr->st_uid, ptr->st_gid)) errExit("chown"); + fs_logger2("mkdir", ptr->name); ptr = ptr->next; } } @@ -122,6 +123,7 @@ void fs_var_log(void) { printf("Mounting tmpfs on /var/log\n"); if (mount("tmpfs", "/var/log", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting /var/log"); + fs_logger("mount tmpfs on /var/log"); build_dirs(); release_all(); @@ -135,6 +137,7 @@ void fs_var_log(void) { errExit("chown"); if (chmod("/var/log/wtmp", S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH ) < 0) errExit("chmod"); + fs_logger("touch /var/log/wtmp"); // create an empty /var/log/btmp file fp = fopen("/var/log/btmp", "w"); @@ -144,6 +147,7 @@ void fs_var_log(void) { errExit("chown"); if (chmod("/var/log/btmp", S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP) < 0) errExit("chmod"); + fs_logger("touch /var/log/btmp"); } else fprintf(stderr, "Warning: cannot mount tmpfs on top of /var/log\n"); @@ -158,6 +162,7 @@ void fs_var_lib(void) { printf("Mounting tmpfs on /var/lib/dhcp\n"); if (mount("tmpfs", "/var/lib/dhcp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting /var/lib/dhcp"); + fs_logger("mount tmpfs on /var/lib/dhcp"); // isc dhcp server requires a /var/lib/dhcp/dhcpd.leases file FILE *fp = fopen("/var/lib/dhcp/dhcpd.leases", "w"); @@ -169,6 +174,7 @@ void fs_var_lib(void) { errExit("chown"); if (chmod("/var/lib/dhcp/dhcpd.leases", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) errExit("chmod"); + fs_logger("touch /var/lib/dhcp/dhcpd.leases"); } } @@ -178,6 +184,7 @@ void fs_var_lib(void) { printf("Mounting tmpfs on /var/lib/nginx\n"); if (mount("tmpfs", "/var/lib/nginx", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting /var/lib/nginx"); + fs_logger("mount tmpfs on /var/lib/nignx"); } // net-snmp multiserver @@ -186,6 +193,7 @@ void fs_var_lib(void) { printf("Mounting tmpfs on /var/lib/snmp\n"); if (mount("tmpfs", "/var/lib/snmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting /var/lib/snmp"); + fs_logger("mount tmpfs on /var/lib/snmp"); } // this is where sudo remembers its state @@ -194,6 +202,7 @@ void fs_var_lib(void) { printf("Mounting tmpfs on /var/lib/sudo\n"); if (mount("tmpfs", "/var/lib/sudo", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting /var/lib/sudo"); + fs_logger("mount tmpfs on /var/lib/sudo"); } } @@ -204,7 +213,8 @@ void fs_var_cache(void) { if (arg_debug) printf("Mounting tmpfs on /var/cache/apache2\n"); if (mount("tmpfs", "/var/cache/apache2", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) - errExit("mounting /var/cahce/apache2"); + errExit("mounting /var/cache/apache2"); + fs_logger("mount tmpfs on /var/cache/apache2"); } if (stat("/var/cache/lighttpd", &s) == 0) { @@ -212,6 +222,7 @@ void fs_var_cache(void) { printf("Mounting tmpfs on /var/cache/lighttpd\n"); if (mount("tmpfs", "/var/cache/lighttpd", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting /var/cache/lighttpd"); + fs_logger("mount tmpfs on /var/cache/lighttpd"); struct passwd *p = getpwnam("www-data"); uid_t uid = 0; @@ -226,12 +237,14 @@ void fs_var_cache(void) { errExit("mkdir"); if (chown("/var/cache/lighttpd/compress", uid, gid) < 0) errExit("chown"); + fs_logger("mkdir /var/cache/lighttpd/compress"); rv = mkdir("/var/cache/lighttpd/uploads", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); if (rv == -1) errExit("mkdir"); if (chown("/var/cache/lighttpd/uploads", uid, gid) < 0) errExit("chown"); + fs_logger("/var/cache/lighttpd/uploads"); } } @@ -257,6 +270,7 @@ void fs_var_lock(void) { printf("Mounting tmpfs on /var/lock\n"); if (mount("tmpfs", "/var/lock", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) errExit("mounting /lock"); + fs_logger("mount tmpfs on /var/lock"); } else { char *lnk = realpath("/var/lock", NULL); @@ -275,6 +289,7 @@ void fs_var_lock(void) { if (mount("tmpfs", lnk, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) errExit("mounting /var/lock"); free(lnk); + fs_logger("mount tmpfs on /var/lock"); } else { fprintf(stderr, "Warning: /var/lock not mounted\n"); @@ -291,6 +306,7 @@ void fs_var_tmp(void) { printf("Mounting tmpfs on /var/tmp\n"); if (mount("tmpfs", "/var/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) errExit("mounting /var/tmp"); + fs_logger("mount tmpfs on /var/tmp"); } } else { @@ -348,6 +364,7 @@ void fs_var_utmp(void) { printf("Mount the new utmp file\n"); if (mount(UTMP_FILE, "/var/run/utmp", NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind utmp"); + fs_logger("create /var/run/utmp"); } diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c index 95238a956..f8cce219e 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c @@ -119,6 +119,7 @@ static int mkpath(const char* path, mode_t mode) { errExit("strdup"); char* p; + int done = 0; for (p=strchr(file_path+1, '/'); p; p=strchr(p+1, '/')) { *p='\0'; if (mkdir(file_path, mode)==-1) { @@ -133,10 +134,13 @@ static int mkpath(const char* path, mode_t mode) { errExit("chmod"); if (chown(file_path, uid, gid) == -1) errExit("chown"); + done = 1; } *p='/'; } + if (done) + fs_logger2("mkpath", path); free(file_path); return 0; @@ -225,6 +229,7 @@ static void whitelist_path(ProfileEntry *entry) { // create the path if necessary mkpath(path, s.st_mode); + fs_logger2("whitelist", path); // process directory if (S_ISDIR(s.st_mode)) { @@ -442,6 +447,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /tmp directory\n"); if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) errExit("mounting tmpfs on /tmp"); + fs_logger("mount tmpfs on /tmp"); } // /media mountpoint @@ -463,9 +469,10 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /media directory\n"); if (mount("tmpfs", "/media", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /media"); + fs_logger("mount tmpfs on /media"); } - // /media mountpoint + // /var mountpoint if (var_dir) { // keep a copy of real /var directory in RUN_WHITELIST_VAR_DIR int rv = mkdir(RUN_WHITELIST_VAR_DIR, S_IRWXU | S_IRWXG | S_IRWXO); @@ -484,6 +491,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /var directory\n"); if (mount("tmpfs", "/var", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /var"); + fs_logger("mount tmpfs on /var"); } // /dev mountpoint @@ -505,6 +513,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /dev directory\n"); if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /dev"); + fs_logger("mount tmpfs on /dev"); } // /opt mountpoint @@ -526,6 +535,7 @@ void fs_whitelist(void) { printf("Mounting tmpfs on /opt directory\n"); if (mount("tmpfs", "/opt", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /opt"); + fs_logger("mount tmpfs on /opt"); } // go through profile rules again, and interpret whitelist commands diff --git a/src/firejail/main.c b/src/firejail/main.c index 2981683aa..a6e95e963 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -340,7 +340,15 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { caps_print_filter_name(argv[i] + 13); exit(0); } - + else if (strncmp(argv[i], "--fs.print=", 11) == 0) { + // join sandbox by pid or by name + pid_t pid; + if (read_pid(argv[i] + 11, &pid) == 0) + fs_logger_print_log(pid); + else + fs_logger_print_log_name(argv[i] + 11); + exit(0); + } else if (strncmp(argv[i], "--dns.print=", 12) == 0) { // join sandbox by pid or by name pid_t pid; diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c index 6ead5799c..3d54751c7 100644 --- a/src/firejail/pulseaudio.c +++ b/src/firejail/pulseaudio.c @@ -45,6 +45,7 @@ static void disable_file(const char *path, const char *file) { if (mount(RUN_RO_FILE, fname, "none", MS_BIND, "mode=400,gid=0") < 0) errExit("disable file"); } + fs_logger2("blacklist", fname); doexit: free(fname); diff --git a/src/firejail/restrict_users.c b/src/firejail/restrict_users.c index 50a9a9b89..ec65005ba 100644 --- a/src/firejail/restrict_users.c +++ b/src/firejail/restrict_users.c @@ -59,40 +59,6 @@ static USER_LIST *ulist_find(const char *user) { return NULL; } -static int mkpath(const char* path) { - assert(path && *path); - - // work on a copy of the path - char *file_path = strdup(path); - if (!file_path) - errExit("strdup"); - - char* p; - for (p=strchr(file_path+1, '/'); p; p=strchr(p+1, '/')) { - *p='\0'; - if (mkdir(file_path, 0755)==-1) { - if (errno != EEXIST) { - *p='/'; - free(file_path); - return -1; - } - } - else { - if (chmod(file_path, 0755) == -1) - errExit("chmod"); - if (chown(file_path, 0, 0) == -1) - errExit("chown"); - } - - *p='/'; - } - - free(file_path); - return 0; -} - - - static void sanitize_home(void) { assert(getuid() != 0); // this code works only for regular users @@ -117,6 +83,7 @@ static void sanitize_home(void) { // mount tmpfs in the new home if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); + fs_logger("mount tmpfs on /home"); // create user home directory if (mkdir(cfg.homedir, 0755) == -1) { @@ -125,6 +92,7 @@ static void sanitize_home(void) { if (mkdir(cfg.homedir, 0755) == -1) errExit("mkdir"); } + fs_logger2("mkdir", cfg.homedir); // set mode and ownership if (chown(cfg.homedir, s.st_uid, s.st_gid) == -1) @@ -218,6 +186,7 @@ static void sanitize_passwd(void) { // mount-bind tne new password file if (mount(RUN_PASSWD_FILE, "/etc/passwd", "none", MS_BIND, "mode=400,gid=0") < 0) errExit("mount"); + fs_logger("create /etc/passwd"); return; @@ -344,6 +313,7 @@ static void sanitize_group(void) { // mount-bind tne new group file if (mount(RUN_GROUP_FILE, "/etc/group", "none", MS_BIND, "mode=400,gid=0") < 0) errExit("mount"); + fs_logger("create /etc/group"); return; @@ -367,6 +337,7 @@ void restrict_users(void) { // mount tmpfs on top of /home in order to hide it if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); + fs_logger("mount tmpfs on /home"); } sanitize_passwd(); sanitize_group(); diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 2827ca9d3..5ae43dbd1 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c @@ -271,6 +271,7 @@ int sandbox(void* sandbox_arg) { if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) { chk_chroot(); } + fs_logger("install mount namespace"); //**************************** // netfilter etc. @@ -400,7 +401,7 @@ int sandbox(void* sandbox_arg) { pulseaudio_disable(); else pulseaudio_init(); - + //**************************** // networking //**************************** @@ -468,6 +469,8 @@ int sandbox(void* sandbox_arg) { // if any dns server is configured, it is time to set it now fs_resolvconf(); + fs_logger_print(); + fs_logger_change_owner(); // print network configuration if (!arg_quiet) { diff --git a/src/firejail/usage.c b/src/firejail/usage.c index d8f6d6849..70b9cf24e 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c @@ -83,7 +83,11 @@ void usage(void) { printf("\t--dns.print=pid - print DNS configuration of the sandbox identified.\n"); printf("\t\tby PID.\n\n"); - printf("\t--env=name=value - set environment variable in the new sandbox\n"); + printf("\t--env=name=value - set environment variable in the new sandbox\n\n"); + printf("\t--fs.print=name - print the filesystem log for the sandbox identified\n"); + printf("\t\tby name.\n\n"); + printf("\t--fs.print=pid - print the filesystem log for the sandbox identified\n"); + printf("\t\tby PID.\n\n"); printf("\t--help, -? - this help screen.\n\n"); printf("\t--hostname=name - set sandbox hostname.\n\n"); diff --git a/src/firejail/util.c b/src/firejail/util.c index 45f7ec364..6c7476be6 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c @@ -84,6 +84,7 @@ int mkpath_as_root(const char* path) { errExit("strdup"); char* p; + int done = 0; for (p=strchr(file_path+1, '/'); p; p=strchr(p+1, '/')) { *p='\0'; if (mkdir(file_path, 0755)==-1) { @@ -98,11 +99,14 @@ int mkpath_as_root(const char* path) { errExit("chmod"); if (chown(file_path, 0, 0) == -1) errExit("chown"); + done = 1; } *p='/'; } - + if (done) + fs_logger2("mkpath", path); + free(file_path); return 0; } diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 4f9f0cba9..de03af56c 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt @@ -337,6 +337,35 @@ Example: .br $ firejail \-\-env=LD_LIBRARY_PATH=/opt/test/lib +.TP +\fB\-\-fs.print=name +Print the filesystem log for the sandbox identified by name. +.br + +.br +Example: +.br +$ firejail \-\-name=mygame \-\-caps.drop=all warzone2100 & +.br +[...] +.br +$ firejail \-\-fs.print=mygame + +.TP +\fB\-\-fs.print=pid +Print the filesystem log for a sandbox identified by PID. +.br + +.br +Example: +.br +$ firejail \-\-list +.br +3272:netblue:firejail \-\-private firefox +.br +$ firejail \-\-fs.print=3272 + + .TP \fB\-?\fR, \fB\-\-help\fR Print options end exit. diff --git a/todo b/todo index 553933f00..b7754f7ef 100644 --- a/todo +++ b/todo @@ -139,3 +139,11 @@ drwxr-xr-x 3 65534 65534 60 Nov 25 08:09 .. -rw-r--r-- 1 netblue netblue 3392 Nov 25 08:09 .bashrc dr-x------ 2 65534 65534 40 Nov 24 17:53 .mozilla -rw------- 1 netblue netblue 51 Nov 25 08:09 .Xauthority + + +19. move from tmpfs to blacklist +mount tmpfs on /sys/firmware +mount tmpfs on /sys/hypervisor +mount tmpfs on /sys/fs +mount tmpfs on /sys/module +mount tmpfs on /sys/power -- cgit v1.2.3-70-g09d2