aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2018-10-25 22:07:19 +0200
committerLibravatar smitsohu <smitsohu@gmail.com>2018-10-25 22:07:19 +0200
commita7164cb38171c0291fac7f3a0767fe8f1c69b02d (patch)
tree88335663b94f807ebe7efcdb70eaeae80701601e /src
parentmerges (diff)
downloadfirejail-a7164cb38171c0291fac7f3a0767fe8f1c69b02d.tar.gz
firejail-a7164cb38171c0291fac7f3a0767fe8f1c69b02d.tar.zst
firejail-a7164cb38171c0291fac7f3a0767fe8f1c69b02d.zip
experimental: remounts child mount points as well (read-only, read-write, noexec)
Diffstat (limited to 'src')
-rw-r--r--src/firejail/firejail.h8
-rw-r--r--src/firejail/fs.c156
-rw-r--r--src/firejail/mountinfo.c205
-rw-r--r--src/firejail/pulseaudio.c14
-rw-r--r--src/firejail/x11.c10
5 files changed, 302 insertions, 91 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..46124c482 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,138 @@ 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 return;
490 // allow only user owned directories, except the user is root 490 // build array with all mount points that need to get remounted
491 uid_t u = getuid(); 491 char **arr = get_all_mounts(mountid, dir);
492 assert(arr);
493 // remount
494 EUID_ROOT();
495 char **tmp = arr;
496 while (*tmp) {
497 fs_rdonly(*tmp);
498 free(*tmp++);
499 }
500 free(arr);
501}
502
503// remount directory read-write
504static void fs_rdwr(const char *dir) {
505 assert(dir);
506 // check directory exists
492 struct stat s; 507 struct stat s;
493 int rv = stat(path, &s); 508 int rv = stat(dir, &s);
494 if (rv) { 509 if (rv == 0) {
495 free(path); 510 // allow only user owned directories, except the user is root
496 return; 511 uid_t u = getuid();
497 } 512 if (u != 0 && s.st_uid != u) {
498 if (u != 0 && s.st_uid != u) { 513 fwarning("you are not allowed to change %s to read-write\n", dir);
499 fwarning("you are not allowed to change %s to read-write\n", path); 514 return;
500 free(path); 515 }
501 return; 516 unsigned long flags = 0;
502 } 517 get_mount_flags(dir, &flags);
503 // mount --bind /bin /bin 518 if ((flags & MS_RDONLY) == 0)
504 // mount --bind -o remount,rw /bin 519 return;
505 unsigned long flags = 0; 520 flags &= ~MS_RDONLY;
506 get_mount_flags(path, &flags); 521 if (arg_debug)
507 if ((flags & MS_RDONLY) == 0) { 522 printf("Mounting read-write %s\n", dir);
508 free(path); 523 // mount --bind /bin /bin
509 return; 524 // mount --bind -o remount,rw /bin
525 if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0 ||
526 mount(NULL, dir, NULL, flags|MS_BIND|MS_REMOUNT, NULL) < 0)
527 errExit("mount read-write");
528 fs_logger2("read-write", dir);
529 // run a sanity check on /proc/self/mountinfo
530 MountData *mptr = get_last_mount();
531 size_t len = strlen(dir);
532 if (strncmp(mptr->dir, dir, len) != 0 ||
533 (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/'))
534 errLogExit("invalid read-write mount");
510 } 535 }
511 flags &= ~MS_RDONLY; 536}
512 if (mount(path, path, NULL, MS_BIND|MS_REC, NULL) < 0 ||
513 mount(NULL, path, NULL, flags|MS_BIND|MS_REMOUNT|MS_REC, NULL) < 0)
514 errExit("mount read-write");
515 fs_logger2("read-write", path);
516
517 // run a check on /proc/self/mountinfo to validate the mount
518 MountData *mptr = get_last_mount();
519 if (strncmp(mptr->dir, path, strlen(path)) != 0)
520 errLogExit("invalid read-write mount");
521 537
522 free(path); 538// remount directory read-write recursively
539static void fs_rdwr_rec(const char *dir) {
540 assert(dir);
541 EUID_USER();
542 // get mount point of the directory
543 int mountid = get_mount_id(dir);
544 if (mountid == 0)
545 return;
546 // build array with all mount points that need to get remounted
547 char **arr = get_all_mounts(mountid, dir);
548 assert(arr);
549 // remount
550 EUID_ROOT();
551 char **tmp = arr;
552 while (*tmp) {
553 fs_rdwr(*tmp);
554 free(*tmp++);
555 }
556 free(arr);
523} 557}
524 558
559// remount directory noexec, nodev, nosuid
525void fs_noexec(const char *dir) { 560void fs_noexec(const char *dir) {
526 assert(dir); 561 assert(dir);
527 // check directory exists 562 // check directory exists
528 struct stat s; 563 struct stat s;
529 int rv = stat(dir, &s); 564 int rv = stat(dir, &s);
530 if (rv == 0) { 565 if (rv == 0) {
531 // mount --bind /bin /bin
532 // mount --bind -o remount,ro /bin
533 unsigned long flags = 0; 566 unsigned long flags = 0;
534 get_mount_flags(dir, &flags); 567 get_mount_flags(dir, &flags);
535 if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID)) 568 if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID))
536 return; 569 return;
537 flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID; 570 flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID;
571 if (arg_debug)
572 printf("Mounting noexec %s\n", dir);
573 // mount --bind /bin /bin
574 // mount --bind -o remount,noexec /bin
538 if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0 || 575 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) 576 mount(NULL, dir, NULL, flags|MS_BIND|MS_REMOUNT, NULL) < 0)
540 errExit("mount noexec"); 577 errExit("mount noexec");
541 fs_logger2("noexec", dir); 578 fs_logger2("noexec", dir);
542 } 579 }
543} 580}
544 581
582// remount directory noexec, nodev, nosuid recursively
583void fs_noexec_rec(const char *dir) {
584 assert(dir);
585 EUID_USER();
586 // get mount point of the directory
587 int mountid = get_mount_id(dir);
588 if (mountid == 0)
589 return;
590 // build array with all mount points that need to get remounted
591 char **arr = get_all_mounts(mountid, dir);
592 assert(arr);
593 // remount
594 EUID_ROOT();
595 char **tmp = arr;
596 while (*tmp) {
597 fs_noexec(*tmp);
598 free(*tmp++);
599 }
600 free(arr);
601}
602
545// Disable /mnt, /media, /run/mount and /run/media access 603// Disable /mnt, /media, /run/mount and /run/media access
546void fs_mnt(const int enforce) { 604void fs_mnt(const int enforce) {
547 if (enforce) { 605 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;