aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2018-10-26 10:05:08 -0500
committerLibravatar GitHub <noreply@github.com>2018-10-26 10:05:08 -0500
commit158eddba0ed09ae5da3800bf5f5aa25f31a906a6 (patch)
treef50824f65dc2470dd9b8200ee154135efb218ed0 /src
parentmerges (diff)
parentcleanup (diff)
downloadfirejail-158eddba0ed09ae5da3800bf5f5aa25f31a906a6.tar.gz
firejail-158eddba0ed09ae5da3800bf5f5aa25f31a906a6.tar.zst
firejail-158eddba0ed09ae5da3800bf5f5aa25f31a906a6.zip
Merge pull request #2218 from smitsohu/mounts2
experimental: remounts child mount points as well
Diffstat (limited to 'src')
-rw-r--r--src/firejail/firejail.h8
-rw-r--r--src/firejail/fs.c160
-rw-r--r--src/firejail/mountinfo.c205
-rw-r--r--src/firejail/pulseaudio.c14
-rw-r--r--src/firejail/x11.c10
5 files changed, 307 insertions, 90 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 19b8480f8..d5733e678 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -440,8 +440,10 @@ void preproc_clean_run(void);
440void fs_blacklist(void); 440void fs_blacklist(void);
441// remount a directory read-only 441// remount a directory read-only
442void fs_rdonly(const char *dir); 442void fs_rdonly(const char *dir);
443void fs_rdonly_rec(const char *dir);
443// remount a directory noexec, nodev and nosuid 444// remount a directory noexec, nodev and nosuid
444void fs_noexec(const char *dir); 445void fs_noexec(const char *dir);
446void fs_noexec_rec(const char *dir);
445// mount /proc and /sys directories 447// mount /proc and /sys directories
446void fs_proc_sys_dev_boot(void); 448void fs_proc_sys_dev_boot(void);
447// build a basic read-only filesystem 449// build a basic read-only filesystem
@@ -550,12 +552,16 @@ int invalid_sandbox(const pid_t pid);
550// The return value points to a static area, and will be overwritten by subsequent calls. 552// The return value points to a static area, and will be overwritten by subsequent calls.
551// The function does an exit(1) if anything goes wrong. 553// The function does an exit(1) if anything goes wrong.
552typedef struct { 554typedef struct {
555 int mountid; // id of the mount
553 char *fsname; // the pathname of the directory in the filesystem which forms the root of this mount 556 char *fsname; // the pathname of the directory in the filesystem which forms the root of this mount
554 char *dir; // mount destination 557 char *dir; // mount destination
555 char *fstype; // filesystem type 558 char *fstype; // filesystem type
556} MountData; 559} MountData;
557MountData *get_last_mount(void);
558 560
561// mountinfo.c
562MountData *get_last_mount(void);
563int get_mount_id(const char *path);
564char **get_all_mounts(const int mountid, const char *path);
559 565
560// fs_var.c 566// fs_var.c
561void fs_var_log(void); // mounting /var/log 567void fs_var_log(void); // mounting /var/log
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index 3ce2c7571..6fe9d56aa 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -29,12 +29,14 @@
29#include <errno.h> 29#include <errno.h>
30#include <fcntl.h> 30#include <fcntl.h>
31 31
32#define MAX_BUF 4096
32// check noblacklist statements not matched by a proper blacklist in disable-*.inc files 33// check noblacklist statements not matched by a proper blacklist in disable-*.inc files
33//#define TEST_NO_BLACKLIST_MATCHING 34//#define TEST_NO_BLACKLIST_MATCHING
34 35
35 36
36 37
37static void fs_rdwr(const char *dir); 38static void fs_rdwr(const char *dir);
39static void fs_rdwr_rec(const char *dir);
38 40
39 41
40 42
@@ -147,21 +149,15 @@ static void disable_file(OPERATION op, const char *filename) {
147 } 149 }
148 } 150 }
149 else if (op == MOUNT_READONLY) { 151 else if (op == MOUNT_READONLY) {
150 if (arg_debug) 152 fs_rdonly_rec(fname);
151 printf("Mounting read-only %s\n", fname);
152 fs_rdonly(fname);
153// todo: last_disable = SUCCESSFUL; 153// todo: last_disable = SUCCESSFUL;
154 } 154 }
155 else if (op == MOUNT_RDWR) { 155 else if (op == MOUNT_RDWR) {
156 if (arg_debug) 156 fs_rdwr_rec(fname);
157 printf("Mounting read-only %s\n", fname);
158 fs_rdwr(fname);
159// todo: last_disable = SUCCESSFUL; 157// todo: last_disable = SUCCESSFUL;
160 } 158 }
161 else if (op == MOUNT_NOEXEC) { 159 else if (op == MOUNT_NOEXEC) {
162 if (arg_debug) 160 fs_noexec_rec(fname);
163 printf("Mounting noexec %s\n", fname);
164 fs_noexec(fname);
165// todo: last_disable = SUCCESSFUL; 161// todo: last_disable = SUCCESSFUL;
166 } 162 }
167 else if (op == MOUNT_TMPFS) { 163 else if (op == MOUNT_TMPFS) {
@@ -457,9 +453,10 @@ static int get_mount_flags(const char *path, unsigned long *flags) {
457 453
458//*********************************************** 454//***********************************************
459// mount namespace 455// mount namespace
456// - functions need fully resolved paths
460//*********************************************** 457//***********************************************
461 458
462// remount a directory read-only 459// remount directory read-only
463void fs_rdonly(const char *dir) { 460void fs_rdonly(const char *dir) {
464 assert(dir); 461 assert(dir);
465 // check directory exists 462 // check directory exists
@@ -471,77 +468,144 @@ void fs_rdonly(const char *dir) {
471 if ((flags & MS_RDONLY) == MS_RDONLY) 468 if ((flags & MS_RDONLY) == MS_RDONLY)
472 return; 469 return;
473 flags |= MS_RDONLY; 470 flags |= MS_RDONLY;
471 if (arg_debug)
472 printf("Mounting read-only %s\n", dir);
474 // mount --bind /bin /bin 473 // mount --bind /bin /bin
475 // mount --bind -o remount,ro /bin 474 // mount --bind -o remount,ro /bin
476 if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0 || 475 if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0 ||
477 mount(NULL, dir, NULL, flags|MS_BIND|MS_REMOUNT|MS_REC, NULL) < 0) 476 mount(NULL, dir, NULL, flags|MS_BIND|MS_REMOUNT, NULL) < 0)
478 errExit("mount read-only"); 477 errExit("mount read-only");
479 fs_logger2("read-only", dir); 478 fs_logger2("read-only", dir);
480 } 479 }
481} 480}
482 481
483static void fs_rdwr(const char *dir) { 482// remount directory read-only recursively
483void fs_rdonly_rec(const char *dir) {
484 assert(dir); 484 assert(dir);
485 // check directory exists and ensure we have a resolved path 485 EUID_USER();
486 // the resolved path allows to run a sanity check after the mount 486 // get mount point of the directory
487 char *path = realpath(dir, NULL); 487 int mountid = get_mount_id(dir);
488 if (path == NULL) 488 if (mountid == 0) {
489 return; 489 EUID_ROOT();
490 // allow only user owned directories, except the user is root
491 uid_t u = getuid();
492 struct stat s;
493 int rv = stat(path, &s);
494 if (rv) {
495 free(path);
496 return; 490 return;
497 } 491 }
498 if (u != 0 && s.st_uid != u) { 492 // build array with all mount points that need to get remounted
499 fwarning("you are not allowed to change %s to read-write\n", path); 493 char **arr = get_all_mounts(mountid, dir);
500 free(path); 494 assert(arr);
501 return; 495 // remount
496 EUID_ROOT();
497 char **tmp = arr;
498 while (*tmp) {
499 fs_rdonly(*tmp);
500 free(*tmp++);
501 }
502 free(arr);
503}
504
505// remount directory read-write
506static void fs_rdwr(const char *dir) {
507 assert(dir);
508 // check directory exists
509 struct stat s;
510 int rv = stat(dir, &s);
511 if (rv == 0) {
512 // allow only user owned directories, except the user is root
513 uid_t u = getuid();
514 if (u != 0 && s.st_uid != u) {
515 fwarning("you are not allowed to change %s to read-write\n", dir);
516 return;
517 }
518 unsigned long flags = 0;
519 get_mount_flags(dir, &flags);
520 if ((flags & MS_RDONLY) == 0)
521 return;
522 flags &= ~MS_RDONLY;
523 if (arg_debug)
524 printf("Mounting read-write %s\n", dir);
525 // mount --bind /bin /bin
526 // mount --bind -o remount,rw /bin
527 if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0 ||
528 mount(NULL, dir, NULL, flags|MS_BIND|MS_REMOUNT, NULL) < 0)
529 errExit("mount read-write");
530 fs_logger2("read-write", dir);
531 // run a sanity check on /proc/self/mountinfo
532 MountData *mptr = get_last_mount();
533 size_t len = strlen(dir);
534 if (strncmp(mptr->dir, dir, len) != 0 ||
535 (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/'))
536 errLogExit("invalid read-write mount");
502 } 537 }
503 // mount --bind /bin /bin 538}
504 // mount --bind -o remount,rw /bin 539
505 unsigned long flags = 0; 540// remount directory read-write recursively
506 get_mount_flags(path, &flags); 541static void fs_rdwr_rec(const char *dir) {
507 if ((flags & MS_RDONLY) == 0) { 542 assert(dir);
508 free(path); 543 EUID_USER();
544 // get mount point of the directory
545 int mountid = get_mount_id(dir);
546 if (mountid == 0) {
547 EUID_ROOT();
509 return; 548 return;
510 } 549 }
511 flags &= ~MS_RDONLY; 550 // build array with all mount points that need to get remounted
512 if (mount(path, path, NULL, MS_BIND|MS_REC, NULL) < 0 || 551 char **arr = get_all_mounts(mountid, dir);
513 mount(NULL, path, NULL, flags|MS_BIND|MS_REMOUNT|MS_REC, NULL) < 0) 552 assert(arr);
514 errExit("mount read-write"); 553 // remount
515 fs_logger2("read-write", path); 554 EUID_ROOT();
516 555 char **tmp = arr;
517 // run a check on /proc/self/mountinfo to validate the mount 556 while (*tmp) {
518 MountData *mptr = get_last_mount(); 557 fs_rdwr(*tmp);
519 if (strncmp(mptr->dir, path, strlen(path)) != 0) 558 free(*tmp++);
520 errLogExit("invalid read-write mount"); 559 }
521 560 free(arr);
522 free(path);
523} 561}
524 562
563// remount directory noexec, nodev, nosuid
525void fs_noexec(const char *dir) { 564void fs_noexec(const char *dir) {
526 assert(dir); 565 assert(dir);
527 // check directory exists 566 // check directory exists
528 struct stat s; 567 struct stat s;
529 int rv = stat(dir, &s); 568 int rv = stat(dir, &s);
530 if (rv == 0) { 569 if (rv == 0) {
531 // mount --bind /bin /bin
532 // mount --bind -o remount,ro /bin
533 unsigned long flags = 0; 570 unsigned long flags = 0;
534 get_mount_flags(dir, &flags); 571 get_mount_flags(dir, &flags);
535 if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID)) 572 if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID))
536 return; 573 return;
537 flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID; 574 flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID;
575 if (arg_debug)
576 printf("Mounting noexec %s\n", dir);
577 // mount --bind /bin /bin
578 // mount --bind -o remount,noexec /bin
538 if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0 || 579 if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0 ||
539 mount(NULL, dir, NULL, flags|MS_BIND|MS_REMOUNT|MS_REC, NULL) < 0) 580 mount(NULL, dir, NULL, flags|MS_BIND|MS_REMOUNT, NULL) < 0)
540 errExit("mount noexec"); 581 errExit("mount noexec");
541 fs_logger2("noexec", dir); 582 fs_logger2("noexec", dir);
542 } 583 }
543} 584}
544 585
586// remount directory noexec, nodev, nosuid recursively
587void fs_noexec_rec(const char *dir) {
588 assert(dir);
589 EUID_USER();
590 // get mount point of the directory
591 int mountid = get_mount_id(dir);
592 if (mountid == 0) {
593 EUID_ROOT();
594 return;
595 }
596 // build array with all mount points that need to get remounted
597 char **arr = get_all_mounts(mountid, dir);
598 assert(arr);
599 // remount
600 EUID_ROOT();
601 char **tmp = arr;
602 while (*tmp) {
603 fs_noexec(*tmp);
604 free(*tmp++);
605 }
606 free(arr);
607}
608
545// Disable /mnt, /media, /run/mount and /run/media access 609// Disable /mnt, /media, /run/mount and /run/media access
546void fs_mnt(const int enforce) { 610void fs_mnt(const int enforce) {
547 if (enforce) { 611 if (enforce) {
diff --git a/src/firejail/mountinfo.c b/src/firejail/mountinfo.c
index 4a7816901..b7760ba67 100644
--- a/src/firejail/mountinfo.c
+++ b/src/firejail/mountinfo.c
@@ -19,16 +19,19 @@
19*/ 19*/
20 20
21#include "firejail.h" 21#include "firejail.h"
22#include <fcntl.h>
22 23
23#define MAX_BUF 4096 24#define MAX_BUF 4096
25
24static char mbuf[MAX_BUF]; 26static char mbuf[MAX_BUF];
25static MountData mdata; 27static MountData mdata;
26 28
29
27// Convert octal escape sequence to decimal value 30// Convert octal escape sequence to decimal value
28static int read_oct(const char *path) { 31static int read_oct(const char *path) {
29 int decimal = 0; 32 int decimal = 0;
30 int digit, i; 33 int digit, i;
31 // there are always three octal digits 34 // there are always exactly three octal digits
32 for (i = 1; i < 4; i++) { 35 for (i = 1; i < 4; i++) {
33 digit = *(path + i); 36 digit = *(path + i);
34 if (digit < '0' || digit > '7') { 37 if (digit < '0' || digit > '7') {
@@ -61,43 +64,38 @@ static void unmangle_path(char *path) {
61 } 64 }
62} 65}
63 66
64// Get info regarding the last kernel mount operation. 67// Parse a line from /proc/self/mountinfo,
65// The return value points to a static area, and will be overwritten by subsequent calls. 68// the function does an exit(1) if anything goes wrong.
66// The function does an exit(1) if anything goes wrong. 69static void parse_line(char *line, MountData *output) {
67MountData *get_last_mount(void) { 70 assert(line && *line);
68 // open /proc/self/mountinfo 71 memset(output, 0, sizeof(*output));
69 FILE *fp = fopen("/proc/self/mountinfo", "r"); 72 // extract filesystem name, directory and filesystem types
70 if (!fp)
71 goto errexit;
72
73 mbuf[0] = '\0';
74 while (fgets(mbuf, MAX_BUF, fp));
75 fclose(fp);
76 if (arg_debug)
77 printf("%s", mbuf);
78
79 // extract filesystem name, directory and filesystem type
80 // examples: 73 // examples:
81 // 587 543 8:1 /tmp /etc rw,relatime master:1 - ext4 /dev/sda1 rw,errors=remount-ro,data=ordered 74 // 587 543 8:1 /tmp /etc rw,relatime master:1 - ext4 /dev/sda1 rw,errors=remount-ro,data=ordered
82 // mdata.fsname: /tmp 75 // output.mountid: 587
83 // mdata.dir: /etc 76 // output.fsname: /tmp
84 // mdata.fstype: ext4 77 // output.dir: /etc
78 // output.fstype: ext4
85 // 585 564 0:76 / /home/netblue/.cache rw,nosuid,nodev - tmpfs tmpfs rw 79 // 585 564 0:76 / /home/netblue/.cache rw,nosuid,nodev - tmpfs tmpfs rw
86 // mdata.fsname: / 80 // output.mountid: 585
87 // mdata.dir: /home/netblue/.cache 81 // output.fsname: /
88 // mdata.fstype: tmpfs 82 // output.dir: /home/netblue/.cache
89 memset(&mdata, 0, sizeof(mdata)); 83 // output.fstype: tmpfs
90 char *ptr = strtok(mbuf, " "); 84
85 char *ptr = strtok(line, " ");
91 if (!ptr) 86 if (!ptr)
92 goto errexit; 87 goto errexit;
93 88 if (ptr != line)
89 goto errexit;
90 output->mountid = atoi(ptr);
94 int cnt = 1; 91 int cnt = 1;
92
95 while ((ptr = strtok(NULL, " ")) != NULL) { 93 while ((ptr = strtok(NULL, " ")) != NULL) {
96 cnt++; 94 cnt++;
97 if (cnt == 4) 95 if (cnt == 4)
98 mdata.fsname = ptr; 96 output->fsname = ptr;
99 else if (cnt == 5) { 97 else if (cnt == 5) {
100 mdata.dir = ptr; 98 output->dir = ptr;
101 break; 99 break;
102 } 100 }
103 } 101 }
@@ -109,21 +107,156 @@ MountData *get_last_mount(void) {
109 ptr = strtok(NULL, " "); 107 ptr = strtok(NULL, " ");
110 if (!ptr) 108 if (!ptr)
111 goto errexit; 109 goto errexit;
112 mdata.fstype = ptr++; 110 output->fstype = ptr++;
113 111
114 if (mdata.fsname == NULL || 112
115 mdata.dir == NULL || 113 if (output->mountid == 0 ||
116 mdata.fstype == NULL) 114 output->fsname == NULL ||
115 output->dir == NULL ||
116 output->fstype == NULL)
117 goto errexit; 117 goto errexit;
118 118
119 unmangle_path(mdata.fsname); 119 // restore empty spaces
120 unmangle_path(mdata.dir); 120 unmangle_path(output->fsname);
121 unmangle_path(output->dir);
122
123 return;
124
125errexit:
126 fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n");
127 exit(1);
128}
129
130// The return value points to a static area, and will be overwritten by subsequent calls.
131MountData *get_last_mount(void) {
132 // open /proc/self/mountinfo
133 FILE *fp = fopen("/proc/self/mountinfo", "re");
134 if (!fp) {
135 perror("fopen");
136 fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n");
137 exit(1);
138 }
139
140 mbuf[0] = '\0';
141 // go to the last line
142 while (fgets(mbuf, MAX_BUF, fp));
143 fclose(fp);
144 if (arg_debug)
145 printf("%s", mbuf);
146
147 parse_line(mbuf, &mdata);
121 148
122 if (arg_debug) 149 if (arg_debug)
123 printf("fsname=%s dir=%s fstype=%s\n", mdata.fsname, mdata.dir, mdata.fstype); 150 printf("mountid=%d fsname=%s dir=%s fstype=%s\n", mdata.mountid, mdata.fsname, mdata.dir, mdata.fstype);
124 return &mdata; 151 return &mdata;
152}
153
154// Extract the mount id from /proc/self/fdinfo and return it.
155int get_mount_id(const char *path) {
156 EUID_ASSERT();
157 int fd = open(path, O_PATH|O_CLOEXEC);
158 if (fd == -1)
159 return 0;
160
161 char *fdinfo;
162 if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1)
163 errExit("asprintf");
164 EUID_ROOT();
165 FILE *fp = fopen(fdinfo, "re");
166 EUID_USER();
167 if (!fp)
168 goto errexit;
169 // go to the last line
170 char buf[MAX_BUF];
171 while (fgets(buf, MAX_BUF, fp));
172 fclose(fp);
173 close(fd);
174 // go to the mount id
175 if (strncmp(buf, "mnt_id:", 7) != 0)
176 goto errexit;
177 char *ptr = buf + 7;
178 while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
179 ptr++;
180 }
181 if (*ptr == '\0')
182 goto errexit;
183 free(fdinfo);
184
185 return atoi(ptr);
125 186
126errexit: 187errexit:
127 fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); 188 fprintf(stderr, "Error: cannot read file in /proc/self/fdinfo\n");
128 exit(1); 189 exit(1);
129} 190}
191
192// Return array with all paths that might need a remount.
193char **get_all_mounts(const int mountid, const char *path) {
194 // open /proc/self/mountinfo
195 FILE *fp = fopen("/proc/self/mountinfo", "re");
196 if (!fp) {
197 perror("fopen");
198 fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n");
199 exit(1);
200 }
201
202 size_t size = 32;
203 size_t cnt = 0;
204 char **rv = malloc(size * sizeof(*rv));
205 if (!rv)
206 errExit("malloc");
207
208 // read /proc/self/mountinfo
209 size_t pathlen = strlen(path);
210 int found = 0;
211 while (fgets(mbuf, MAX_BUF, fp)) {
212 // find mount point with mount id
213 if (!found) {
214 parse_line(mbuf, &mdata);
215 if (mdata.mountid == mountid) {
216 // don't remount blacklisted paths,
217 // give up if mount id has been reassigned
218 if (strstr(mdata.fsname, "firejail.ro.dir") ||
219 strstr(mdata.fsname, "firejail.ro.file") ||
220 strncmp(mdata.dir, path, strlen(mdata.dir)))
221 break;
222
223 *rv = strdup(path);
224 if (*rv == NULL)
225 errExit("strdup");
226 cnt++;
227 found = 1;
228 continue;
229 }
230 else
231 continue;
232 }
233 // from here on add all mount points below path
234 parse_line(mbuf, &mdata);
235 if (strncmp(mdata.dir, path, pathlen) == 0 &&
236 mdata.dir[pathlen] == '/' &&
237 strstr(mdata.fsname, "firejail.ro.dir") == NULL &&
238 strstr(mdata.fsname, "firejail.ro.file") == NULL) {
239
240 if (cnt >= size) {
241 size *= 2;
242 rv = realloc(rv, size * sizeof(*rv));
243 if (!rv)
244 errExit("realloc");
245 }
246 rv[cnt] = strdup(mdata.dir);
247 if (!rv[cnt])
248 errExit("strdup");
249 cnt++;
250 }
251 }
252 if (cnt == size) {
253 size++;
254 rv = realloc(rv, size * sizeof(*rv));
255 if (!rv)
256 errExit("realloc");
257 }
258 rv[cnt] = NULL; // end of the array
259
260 fclose(fp);
261 return rv;
262}
diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c
index e6696ecb4..4ddaba7ed 100644
--- a/src/firejail/pulseaudio.c
+++ b/src/firejail/pulseaudio.c
@@ -20,6 +20,7 @@
20#include "firejail.h" 20#include "firejail.h"
21#include <sys/types.h> 21#include <sys/types.h>
22#include <sys/stat.h> 22#include <sys/stat.h>
23#include <sys/statvfs.h>
23#include <sys/mount.h> 24#include <sys/mount.h>
24#include <dirent.h> 25#include <dirent.h>
25#include <sys/wait.h> 26#include <sys/wait.h>
@@ -82,10 +83,8 @@ void pulseaudio_init(void) {
82 // create the new user pulseaudio directory 83 // create the new user pulseaudio directory
83 if (mkdir(RUN_PULSE_DIR, 0700) == -1) 84 if (mkdir(RUN_PULSE_DIR, 0700) == -1)
84 errExit("mkdir"); 85 errExit("mkdir");
85 // make it a mount point and add mount flags 86 // mount it nosuid, noexec, nodev
86 if (mount(RUN_PULSE_DIR, RUN_PULSE_DIR, NULL, MS_BIND, NULL) < 0 || 87 fs_noexec(RUN_PULSE_DIR);
87 mount(NULL, RUN_PULSE_DIR, NULL, MS_NOEXEC|MS_NODEV|MS_NOSUID|MS_BIND|MS_REMOUNT, NULL) < 0)
88 errExit("mount RUN_PULSE_DIR");
89 88
90 // create the new client.conf file 89 // create the new client.conf file
91 char *pulsecfg = NULL; 90 char *pulsecfg = NULL;
@@ -189,7 +188,12 @@ void pulseaudio_init(void) {
189 // confirm the actual mount destination is owned by the user 188 // confirm the actual mount destination is owned by the user
190 if (fstat(fd, &s) == -1 || s.st_uid != getuid()) 189 if (fstat(fd, &s) == -1 || s.st_uid != getuid())
191 errExit("fstat"); 190 errExit("fstat");
192 191 // preserve a read-only mount
192 struct statvfs vfs;
193 if (fstatvfs(fd, &vfs) == -1)
194 errExit("fstatvfs");
195 if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY)
196 fs_rdonly(RUN_PULSE_DIR);
193 // mount via the link in /proc/self/fd 197 // mount via the link in /proc/self/fd
194 char *proc; 198 char *proc;
195 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) 199 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
diff --git a/src/firejail/x11.c b/src/firejail/x11.c
index 7d02701c9..9a15a06c8 100644
--- a/src/firejail/x11.c
+++ b/src/firejail/x11.c
@@ -20,6 +20,7 @@
20#include "firejail.h" 20#include "firejail.h"
21#include <sys/types.h> 21#include <sys/types.h>
22#include <sys/stat.h> 22#include <sys/stat.h>
23#include <sys/statvfs.h>
23#include <sys/socket.h> 24#include <sys/socket.h>
24#include <sys/un.h> 25#include <sys/un.h>
25#include <unistd.h> 26#include <unistd.h>
@@ -1163,6 +1164,9 @@ void x11_xorg(void) {
1163 unlink(tmpfname); 1164 unlink(tmpfname);
1164 umount("/tmp"); 1165 umount("/tmp");
1165 1166
1167 // remount RUN_XAUTHORITY_SEC_FILE noexec, nodev, nosuid
1168 fs_noexec(RUN_XAUTHORITY_SEC_FILE);
1169
1166 // Ensure there is already a file in the usual location, so that bind-mount below will work. 1170 // Ensure there is already a file in the usual location, so that bind-mount below will work.
1167 char *dest; 1171 char *dest;
1168 if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1) 1172 if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1)
@@ -1184,6 +1188,12 @@ void x11_xorg(void) {
1184 fprintf(stderr, "Error: .Xauthority is not a user owned regular file\n"); 1188 fprintf(stderr, "Error: .Xauthority is not a user owned regular file\n");
1185 exit(1); 1189 exit(1);
1186 } 1190 }
1191 // preserve a read-only mount
1192 struct statvfs vfs;
1193 if (fstatvfs(fd, &vfs) == -1)
1194 errExit("fstatvfs");
1195 if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY)
1196 fs_rdonly(RUN_XAUTHORITY_SEC_FILE);
1187 1197
1188 // mount via the link in /proc/self/fd 1198 // mount via the link in /proc/self/fd
1189 char *proc; 1199 char *proc;