aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2021-06-11 12:28:43 +0200
committerLibravatar smitsohu <smitsohu@gmail.com>2021-06-11 12:28:59 +0200
commitb55d61228778d9d3d397c99af52350a3ff136659 (patch)
tree40240a366cdc892d8072f266822279073cf1b135
parentMerge pull request #4348 from NetSysFire/patch-1 (diff)
downloadfirejail-b55d61228778d9d3d397c99af52350a3ff136659.tar.gz
firejail-b55d61228778d9d3d397c99af52350a3ff136659.tar.zst
firejail-b55d61228778d9d3d397c99af52350a3ff136659.zip
follow-up
PR #4349
-rw-r--r--src/firejail/firejail.h9
-rw-r--r--src/firejail/fs.c18
-rw-r--r--src/firejail/pulseaudio.c62
-rw-r--r--src/firejail/util.c9
-rw-r--r--src/firejail/x11.c15
5 files changed, 57 insertions, 56 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 10133142a..c442a97bf 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -45,6 +45,15 @@
45 assert(s.st_gid == gid);\ 45 assert(s.st_gid == gid);\
46 assert((s.st_mode & 07777) == (mode));\ 46 assert((s.st_mode & 07777) == (mode));\
47 } while (0) 47 } while (0)
48#define ASSERT_PERMS_AS_USER(file, uid, gid, mode) \
49 do { \
50 assert(file);\
51 struct stat s;\
52 if (stat_as_user(file, &s) == -1) errExit("stat");\
53 assert(s.st_uid == uid);\
54 assert(s.st_gid == gid);\
55 assert((s.st_mode & 07777) == (mode));\
56 } while (0)
48#define ASSERT_PERMS_FD(fd, uid, gid, mode) \ 57#define ASSERT_PERMS_FD(fd, uid, gid, mode) \
49 do { \ 58 do { \
50 struct stat s;\ 59 struct stat s;\
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index 01182bd2c..bf78f8a17 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -77,7 +77,7 @@ static void disable_file(OPERATION op, const char *filename) {
77 77
78 EUID_ROOT(); 78 EUID_ROOT();
79 int err = bind_mount_path_to_fd(RUN_RO_DIR, fd); 79 int err = bind_mount_path_to_fd(RUN_RO_DIR, fd);
80 if (err < 0) 80 if (err != 0)
81 err = bind_mount_path_to_fd(RUN_RO_FILE, fd); 81 err = bind_mount_path_to_fd(RUN_RO_FILE, fd);
82 EUID_USER(); 82 EUID_USER();
83 close(fd); 83 close(fd);
@@ -655,8 +655,13 @@ static void fs_remount_rec(const char *dir, OPERATION op) {
655// resolve a path and remount it 655// resolve a path and remount it
656void fs_remount(const char *path, OPERATION op, int rec) { 656void fs_remount(const char *path, OPERATION op, int rec) {
657 assert(path); 657 assert(path);
658 assert(geteuid() == 0); 658
659 EUID_USER(); 659 int called_as_root = 0;
660 if (geteuid() == 0)
661 called_as_root = 1;
662
663 if (called_as_root)
664 EUID_USER();
660 665
661 char *rpath = realpath(path, NULL); 666 char *rpath = realpath(path, NULL);
662 if (rpath) { 667 if (rpath) {
@@ -666,7 +671,9 @@ void fs_remount(const char *path, OPERATION op, int rec) {
666 fs_remount_simple(rpath, op); 671 fs_remount_simple(rpath, op);
667 free(rpath); 672 free(rpath);
668 } 673 }
669 EUID_ROOT(); 674
675 if (called_as_root)
676 EUID_ROOT();
670} 677}
671 678
672// Disable /mnt, /media, /run/mount and /run/media access 679// Disable /mnt, /media, /run/mount and /run/media access
@@ -821,7 +828,6 @@ void disable_config(void) {
821 828
822 829
823// build a basic read-only filesystem 830// build a basic read-only filesystem
824// top level directories could be links, run no after-mount checks
825void fs_basic_fs(void) { 831void fs_basic_fs(void) {
826 uid_t uid = getuid(); 832 uid_t uid = getuid();
827 833
@@ -831,6 +837,7 @@ void fs_basic_fs(void) {
831 if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) 837 if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0)
832 errExit("mounting /proc"); 838 errExit("mounting /proc");
833 839
840 EUID_USER();
834 if (arg_debug) 841 if (arg_debug)
835 printf("Basic read-only filesystem:\n"); 842 printf("Basic read-only filesystem:\n");
836 if (!arg_writable_etc) { 843 if (!arg_writable_etc) {
@@ -850,6 +857,7 @@ void fs_basic_fs(void) {
850 fs_remount("/lib64", MOUNT_READONLY, 1); 857 fs_remount("/lib64", MOUNT_READONLY, 1);
851 fs_remount("/lib32", MOUNT_READONLY, 1); 858 fs_remount("/lib32", MOUNT_READONLY, 1);
852 fs_remount("/libx32", MOUNT_READONLY, 1); 859 fs_remount("/libx32", MOUNT_READONLY, 1);
860 EUID_ROOT();
853 861
854 // update /var directory in order to support multiple sandboxes running on the same root directory 862 // update /var directory in order to support multiple sandboxes running on the same root directory
855 fs_var_lock(); 863 fs_var_lock();
diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c
index be0f5aea6..f8d4c2f3c 100644
--- a/src/firejail/pulseaudio.c
+++ b/src/firejail/pulseaudio.c
@@ -75,31 +75,34 @@ void pulseaudio_disable(void) {
75 closedir(dir); 75 closedir(dir);
76} 76}
77 77
78static void pulseaudio_fallback(const char *path) {
79 assert(path);
80
81 fmessage("Cannot mount tmpfs on %s/.config/pulse\n", cfg.homedir);
82 env_store_name_val("PULSE_CLIENTCONFIG", path, SETENV);
83}
84
85// disable shm in pulseaudio (issue #69) 78// disable shm in pulseaudio (issue #69)
86void pulseaudio_init(void) { 79void pulseaudio_init(void) {
87 struct stat s;
88
89 // do we have pulseaudio in the system? 80 // do we have pulseaudio in the system?
90 if (stat(PULSE_CLIENT_SYSCONF, &s) == -1) { 81 if (access(PULSE_CLIENT_SYSCONF, R_OK)) {
91 if (arg_debug) 82 if (arg_debug)
92 printf("%s not found\n", PULSE_CLIENT_SYSCONF); 83 printf("Cannot read %s\n", PULSE_CLIENT_SYSCONF);
93 return; 84 return;
94 } 85 }
95 86
87 // create ~/.config/pulse directory if not present
88 char *homeusercfg = NULL;
89 if (asprintf(&homeusercfg, "%s/.config", cfg.homedir) == -1)
90 errExit("asprintf");
91 if (create_empty_dir_as_user(homeusercfg, 0700))
92 fs_logger2("create", homeusercfg);
93
94 free(homeusercfg);
95 if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1)
96 errExit("asprintf");
97 if (create_empty_dir_as_user(homeusercfg, 0700))
98 fs_logger2("create", homeusercfg);
99
96 // create the new user pulseaudio directory 100 // create the new user pulseaudio directory
101 // that will be mounted over ~/.config/pulse
97 if (mkdir(RUN_PULSE_DIR, 0700) == -1) 102 if (mkdir(RUN_PULSE_DIR, 0700) == -1)
98 errExit("mkdir"); 103 errExit("mkdir");
99 selinux_relabel_path(RUN_PULSE_DIR, RUN_PULSE_DIR); 104 selinux_relabel_path(RUN_PULSE_DIR, homeusercfg);
100 // mount it nosuid, noexec, nodev
101 fs_remount(RUN_PULSE_DIR, MOUNT_NOEXEC, 0); 105 fs_remount(RUN_PULSE_DIR, MOUNT_NOEXEC, 0);
102
103 // create the new client.conf file 106 // create the new client.conf file
104 char *pulsecfg = NULL; 107 char *pulsecfg = NULL;
105 if (asprintf(&pulsecfg, "%s/client.conf", RUN_PULSE_DIR) == -1) 108 if (asprintf(&pulsecfg, "%s/client.conf", RUN_PULSE_DIR) == -1)
@@ -116,37 +119,14 @@ void pulseaudio_init(void) {
116 if (set_perms(RUN_PULSE_DIR, getuid(), getgid(), 0700)) 119 if (set_perms(RUN_PULSE_DIR, getuid(), getgid(), 0700))
117 errExit("set_perms"); 120 errExit("set_perms");
118 121
119 // create ~/.config/pulse directory if not present
120 char *homeusercfg = NULL;
121 if (asprintf(&homeusercfg, "%s/.config", cfg.homedir) == -1)
122 errExit("asprintf");
123 if (create_empty_dir_as_user(homeusercfg, 0700))
124 fs_logger2("create", homeusercfg);
125
126 free(homeusercfg);
127 if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1)
128 errExit("asprintf");
129 if (create_empty_dir_as_user(homeusercfg, 0700))
130 fs_logger2("create", homeusercfg);
131
132 // if ~/.config/pulse exists and there are no symbolic links, mount the new directory 122 // if ~/.config/pulse exists and there are no symbolic links, mount the new directory
133 // else set environment variable 123 // else set environment variable
124 EUID_USER();
134 int fd = safer_openat(-1, homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 125 int fd = safer_openat(-1, homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
126 EUID_ROOT();
135 if (fd == -1) { 127 if (fd == -1) {
136 pulseaudio_fallback(pulsecfg); 128 fwarning("not mounting tmpfs on %s\n", homeusercfg);
137 goto out; 129 env_store_name_val("PULSE_CLIENTCONFIG", pulsecfg, SETENV);
138 }
139 // confirm the actual mount destination is owned by the user
140 if (fstat(fd, &s) == -1) { // FUSE
141 if (errno != EACCES)
142 errExit("fstat");
143 close(fd);
144 pulseaudio_fallback(pulsecfg);
145 goto out;
146 }
147 if (s.st_uid != getuid()) {
148 close(fd);
149 pulseaudio_fallback(pulsecfg);
150 goto out; 130 goto out;
151 } 131 }
152 // preserve a read-only mount 132 // preserve a read-only mount
diff --git a/src/firejail/util.c b/src/firejail/util.c
index b8643ff60..edd08bb41 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -981,7 +981,7 @@ int remove_overlay_directory(void) {
981 int fd = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC); 981 int fd = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC);
982 if (fd == -1) { 982 if (fd == -1) {
983 fprintf(stderr, "Error: cannot open %s\n", path); 983 fprintf(stderr, "Error: cannot open %s\n", path);
984 _exit(1); 984 exit(1);
985 } 985 }
986 struct stat s; 986 struct stat s;
987 if (fstat(fd, &s) == -1) 987 if (fstat(fd, &s) == -1)
@@ -991,11 +991,11 @@ int remove_overlay_directory(void) {
991 fprintf(stderr, "Error: %s is a symbolic link\n", path); 991 fprintf(stderr, "Error: %s is a symbolic link\n", path);
992 else 992 else
993 fprintf(stderr, "Error: %s is not a directory\n", path); 993 fprintf(stderr, "Error: %s is not a directory\n", path);
994 _exit(1); 994 exit(1);
995 } 995 }
996 if (s.st_uid != getuid()) { 996 if (s.st_uid != getuid()) {
997 fprintf(stderr, "Error: %s is not owned by the current user\n", path); 997 fprintf(stderr, "Error: %s is not owned by the current user\n", path);
998 _exit(1); 998 exit(1);
999 } 999 }
1000 // chdir to ~/.firejail 1000 // chdir to ~/.firejail
1001 if (fchdir(fd) == -1) 1001 if (fchdir(fd) == -1)
@@ -1187,7 +1187,6 @@ unsigned extract_timeout(const char *str) {
1187 1187
1188void disable_file_or_dir(const char *fname) { 1188void disable_file_or_dir(const char *fname) {
1189 assert(fname); 1189 assert(fname);
1190 assert(geteuid() == 0);
1191 1190
1192 EUID_USER(); 1191 EUID_USER();
1193 int fd = open(fname, O_PATH|O_CLOEXEC); 1192 int fd = open(fname, O_PATH|O_CLOEXEC);
@@ -1207,7 +1206,7 @@ void disable_file_or_dir(const char *fname) {
1207 printf("blacklist %s\n", fname); 1206 printf("blacklist %s\n", fname);
1208 if (S_ISDIR(s.st_mode)) { 1207 if (S_ISDIR(s.st_mode)) {
1209 if (bind_mount_path_to_fd(RUN_RO_DIR, fd) < 0) 1208 if (bind_mount_path_to_fd(RUN_RO_DIR, fd) < 0)
1210 errExit("disable directory"); 1209 errExit("disable directory");
1211 } 1210 }
1212 else { 1211 else {
1213 if (bind_mount_path_to_fd(RUN_RO_FILE, fd) < 0) 1212 if (bind_mount_path_to_fd(RUN_RO_FILE, fd) < 0)
diff --git a/src/firejail/x11.c b/src/firejail/x11.c
index 09956b903..0619ff380 100644
--- a/src/firejail/x11.c
+++ b/src/firejail/x11.c
@@ -1204,14 +1204,13 @@ void x11_xorg(void) {
1204 fmessage("Generating a new .Xauthority file\n"); 1204 fmessage("Generating a new .Xauthority file\n");
1205 mkdir_attr(RUN_XAUTHORITY_SEC_DIR, 0700, getuid(), getgid()); 1205 mkdir_attr(RUN_XAUTHORITY_SEC_DIR, 0700, getuid(), getgid());
1206 // create new Xauthority file in RUN_XAUTHORITY_SEC_DIR 1206 // create new Xauthority file in RUN_XAUTHORITY_SEC_DIR
1207 EUID_USER();
1207 char tmpfname[] = RUN_XAUTHORITY_SEC_DIR "/.Xauth-XXXXXX"; 1208 char tmpfname[] = RUN_XAUTHORITY_SEC_DIR "/.Xauth-XXXXXX";
1208 int fd = mkstemp(tmpfname); 1209 int fd = mkstemp(tmpfname);
1209 if (fd == -1) { 1210 if (fd == -1) {
1210 fprintf(stderr, "Error: cannot create .Xauthority file\n"); 1211 fprintf(stderr, "Error: cannot create .Xauthority file\n");
1211 exit(1); 1212 exit(1);
1212 } 1213 }
1213 if (fchown(fd, getuid(), getgid()) == -1)
1214 errExit("chown");
1215 close(fd); 1214 close(fd);
1216 1215
1217 // run xauth 1216 // run xauth
@@ -1221,8 +1220,6 @@ void x11_xorg(void) {
1221 else 1220 else
1222 sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, RUN_XAUTH_FILE, "-f", tmpfname, 1221 sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, RUN_XAUTH_FILE, "-f", tmpfname,
1223 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted"); 1222 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted");
1224 // remove xauth copy
1225 unlink(RUN_XAUTH_FILE);
1226 1223
1227 // ensure there is already a file ~/.Xauthority, so that bind-mount below will work. 1224 // ensure there is already a file ~/.Xauthority, so that bind-mount below will work.
1228 char *dest; 1225 char *dest;
@@ -1273,10 +1270,12 @@ void x11_xorg(void) {
1273 // mount via the link in /proc/self/fd 1270 // mount via the link in /proc/self/fd
1274 if (arg_debug) 1271 if (arg_debug)
1275 printf("Mounting %s on %s\n", tmpfname, dest); 1272 printf("Mounting %s on %s\n", tmpfname, dest);
1273 EUID_ROOT();
1276 if (bind_mount_by_fd(src, dst)) { 1274 if (bind_mount_by_fd(src, dst)) {
1277 fprintf(stderr, "Error: cannot mount the new .Xauthority file\n"); 1275 fprintf(stderr, "Error: cannot mount the new .Xauthority file\n");
1278 exit(1); 1276 exit(1);
1279 } 1277 }
1278 EUID_USER();
1280 // check /proc/self/mountinfo to confirm the mount is ok 1279 // check /proc/self/mountinfo to confirm the mount is ok
1281 MountData *mptr = get_last_mount(); 1280 MountData *mptr = get_last_mount();
1282 if (strcmp(mptr->dir, dest) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) 1281 if (strcmp(mptr->dir, dest) != 0 || strcmp(mptr->fstype, "tmpfs") != 0)
@@ -1289,9 +1288,10 @@ void x11_xorg(void) {
1289 // blacklist user .Xauthority file if it is not masked already 1288 // blacklist user .Xauthority file if it is not masked already
1290 const char *envar = env_get("XAUTHORITY"); 1289 const char *envar = env_get("XAUTHORITY");
1291 if (envar) { 1290 if (envar) {
1292 char *rp = realpath_as_user(envar); 1291 char *rp = realpath(envar, NULL);
1293 if (rp) { 1292 if (rp) {
1294 if (strcmp(rp, dest) != 0) 1293 if (strcmp(rp, dest) != 0)
1294 // disable_file_or_dir returns with EUID 0
1295 disable_file_or_dir(rp); 1295 disable_file_or_dir(rp);
1296 free(rp); 1296 free(rp);
1297 } 1297 }
@@ -1301,9 +1301,13 @@ void x11_xorg(void) {
1301 free(dest); 1301 free(dest);
1302 1302
1303 // mask RUN_XAUTHORITY_SEC_DIR 1303 // mask RUN_XAUTHORITY_SEC_DIR
1304 EUID_ROOT();
1304 if (mount("tmpfs", RUN_XAUTHORITY_SEC_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) 1305 if (mount("tmpfs", RUN_XAUTHORITY_SEC_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0)
1305 errExit("mounting tmpfs"); 1306 errExit("mounting tmpfs");
1306 fs_logger2("tmpfs", RUN_XAUTHORITY_SEC_DIR); 1307 fs_logger2("tmpfs", RUN_XAUTHORITY_SEC_DIR);
1308
1309 // cleanup
1310 unlink(RUN_XAUTH_FILE);
1307#endif 1311#endif
1308} 1312}
1309 1313
@@ -1352,6 +1356,7 @@ void fs_x11(void) {
1352 MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME, 1356 MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME,
1353 "mode=1777,uid=0,gid=0") < 0) 1357 "mode=1777,uid=0,gid=0") < 0)
1354 errExit("mounting tmpfs on /tmp/.X11-unix"); 1358 errExit("mounting tmpfs on /tmp/.X11-unix");
1359 selinux_relabel_path("/tmp/.X11-unix", "/tmp/.X11-unix");
1355 fs_logger("tmpfs /tmp/.X11-unix"); 1360 fs_logger("tmpfs /tmp/.X11-unix");
1356 1361
1357 // create an empty root-owned file which will have the desired socket bind-mounted over it 1362 // create an empty root-owned file which will have the desired socket bind-mounted over it