aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2018-11-04 19:03:49 +0100
committerLibravatar smitsohu <smitsohu@gmail.com>2018-11-04 19:03:49 +0100
commit35d2aec567c0e9c9b5c79678b1dc762916d5492c (patch)
tree40335d4a7320d830cc5f1717fb8afd6e95532330 /src
parentmount appimages nodev,nosuid (diff)
downloadfirejail-35d2aec567c0e9c9b5c79678b1dc762916d5492c.tar.gz
firejail-35d2aec567c0e9c9b5c79678b1dc762916d5492c.tar.zst
firejail-35d2aec567c0e9c9b5c79678b1dc762916d5492c.zip
recursive remounts: add fallback for old kernels, some improvements
* vanilla kernels before 3.15 don't expose a mount id in /proc/pid/fdinfo files. This is still relevant on Ubuntu 14.04 with 3.13 kernel, CentOS 7 doesn't have this problem. In this case fall back to simple a remount and print a warning. * drop euid switching as it doesn't really serve a purpose here (paths are not opened in reading or writing mode, and we are not doing anything with it) and potentially causes problems when suid programs are sandboxed * more rigorous error handling
Diffstat (limited to 'src')
-rw-r--r--src/firejail/fs.c41
-rw-r--r--src/firejail/mountinfo.c44
2 files changed, 57 insertions, 28 deletions
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index eda46d127..38af1fccf 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -34,7 +34,7 @@
34//#define TEST_NO_BLACKLIST_MATCHING 34//#define TEST_NO_BLACKLIST_MATCHING
35 35
36 36
37 37static int mount_warning = 0; // remember if warning was printed already
38static void fs_rdwr(const char *dir); 38static void fs_rdwr(const char *dir);
39static void fs_rdwr_rec(const char *dir); 39static void fs_rdwr_rec(const char *dir);
40 40
@@ -482,18 +482,23 @@ void fs_rdonly(const char *dir) {
482// remount directory read-only recursively 482// remount directory read-only recursively
483void fs_rdonly_rec(const char *dir) { 483void fs_rdonly_rec(const char *dir) {
484 assert(dir); 484 assert(dir);
485 EUID_USER();
486 // get mount point of the directory 485 // get mount point of the directory
487 int mountid = get_mount_id(dir); 486 int mountid = get_mount_id(dir);
488 if (mountid == -1) { 487 if (mountid == -1)
489 EUID_ROOT(); 488 return;
489 if (mountid == -2) {
490 // falling back to a simple remount on old kernels
491 if (!mount_warning) {
492 fwarning("read-only, read-write and noexec options are not applied recursively\n");
493 mount_warning = 1;
494 }
495 fs_rdonly(dir);
490 return; 496 return;
491 } 497 }
492 // build array with all mount points that need to get remounted 498 // build array with all mount points that need to get remounted
493 char **arr = build_mount_array(mountid, dir); 499 char **arr = build_mount_array(mountid, dir);
494 assert(arr); 500 assert(arr);
495 // remount 501 // remount
496 EUID_ROOT();
497 char **tmp = arr; 502 char **tmp = arr;
498 while (*tmp) { 503 while (*tmp) {
499 fs_rdonly(*tmp); 504 fs_rdonly(*tmp);
@@ -540,18 +545,23 @@ static void fs_rdwr(const char *dir) {
540// remount directory read-write recursively 545// remount directory read-write recursively
541static void fs_rdwr_rec(const char *dir) { 546static void fs_rdwr_rec(const char *dir) {
542 assert(dir); 547 assert(dir);
543 EUID_USER();
544 // get mount point of the directory 548 // get mount point of the directory
545 int mountid = get_mount_id(dir); 549 int mountid = get_mount_id(dir);
546 if (mountid == -1) { 550 if (mountid == -1)
547 EUID_ROOT(); 551 return;
552 if (mountid == -2) {
553 // falling back to a simple remount on old kernels
554 if (!mount_warning) {
555 fwarning("read-only, read-write and noexec options are not applied recursively\n");
556 mount_warning = 1;
557 }
558 fs_rdwr(dir);
548 return; 559 return;
549 } 560 }
550 // build array with all mount points that need to get remounted 561 // build array with all mount points that need to get remounted
551 char **arr = build_mount_array(mountid, dir); 562 char **arr = build_mount_array(mountid, dir);
552 assert(arr); 563 assert(arr);
553 // remount 564 // remount
554 EUID_ROOT();
555 char **tmp = arr; 565 char **tmp = arr;
556 while (*tmp) { 566 while (*tmp) {
557 fs_rdwr(*tmp); 567 fs_rdwr(*tmp);
@@ -586,18 +596,23 @@ void fs_noexec(const char *dir) {
586// remount directory noexec, nodev, nosuid recursively 596// remount directory noexec, nodev, nosuid recursively
587void fs_noexec_rec(const char *dir) { 597void fs_noexec_rec(const char *dir) {
588 assert(dir); 598 assert(dir);
589 EUID_USER();
590 // get mount point of the directory 599 // get mount point of the directory
591 int mountid = get_mount_id(dir); 600 int mountid = get_mount_id(dir);
592 if (mountid == -1) { 601 if (mountid == -1)
593 EUID_ROOT(); 602 return;
603 if (mountid == -2) {
604 // falling back to a simple remount on old kernels
605 if (!mount_warning) {
606 fwarning("read-only, read-write and noexec options are not applied recursively\n");
607 mount_warning = 1;
608 }
609 fs_noexec(dir);
594 return; 610 return;
595 } 611 }
596 // build array with all mount points that need to get remounted 612 // build array with all mount points that need to get remounted
597 char **arr = build_mount_array(mountid, dir); 613 char **arr = build_mount_array(mountid, dir);
598 assert(arr); 614 assert(arr);
599 // remount 615 // remount
600 EUID_ROOT();
601 char **tmp = arr; 616 char **tmp = arr;
602 while (*tmp) { 617 while (*tmp) {
603 fs_noexec(*tmp); 618 fs_noexec(*tmp);
diff --git a/src/firejail/mountinfo.c b/src/firejail/mountinfo.c
index b7e6c6fdd..ab1e501a7 100644
--- a/src/firejail/mountinfo.c
+++ b/src/firejail/mountinfo.c
@@ -153,7 +153,6 @@ MountData *get_last_mount(void) {
153 153
154// Extract the mount id from /proc/self/fdinfo and return it. 154// Extract the mount id from /proc/self/fdinfo and return it.
155int get_mount_id(const char *path) { 155int get_mount_id(const char *path) {
156 EUID_ASSERT();
157 int fd = open(path, O_PATH|O_CLOEXEC); 156 int fd = open(path, O_PATH|O_CLOEXEC);
158 if (fd == -1) 157 if (fd == -1)
159 return -1; 158 return -1;
@@ -161,32 +160,41 @@ int get_mount_id(const char *path) {
161 char *fdinfo; 160 char *fdinfo;
162 if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1) 161 if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1)
163 errExit("asprintf"); 162 errExit("asprintf");
164 EUID_ROOT();
165 FILE *fp = fopen(fdinfo, "re"); 163 FILE *fp = fopen(fdinfo, "re");
166 EUID_USER(); 164 if (!fp) {
167 if (!fp) 165 perror("fopen");
168 goto errexit; 166 fprintf(stderr, "Error: cannot open %s\n", fdinfo);
167 exit(1);
168 }
169 169
170 // read the file 170 // read the file
171 char buf[MAX_BUF]; 171 char buf[MAX_BUF];
172 while (fgets(buf, MAX_BUF, fp)) { 172 if (fgets(buf, MAX_BUF, fp) == NULL) {
173 fprintf(stderr, "Error: cannot read %s\n", fdinfo);
174 exit(1);
175 }
176 do {
173 if (strncmp(buf, "mnt_id:", 7) == 0) { 177 if (strncmp(buf, "mnt_id:", 7) == 0) {
174 char *ptr = buf + 7; 178 char *ptr = buf + 7;
175 while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { 179 while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
176 ptr++; 180 ptr++;
177 } 181 }
178 if (*ptr == '\0') 182 if (*ptr == '\0') {
179 goto errexit; 183 fprintf(stderr, "Error: cannot read %s\n", fdinfo);
184 exit(1);
185 }
180 fclose(fp); 186 fclose(fp);
181 close(fd); 187 close(fd);
182 free(fdinfo); 188 free(fdinfo);
183 return atoi(ptr); 189 return atoi(ptr);
184 } 190 }
185 } 191 } while (fgets(buf, MAX_BUF, fp));
186 192
187errexit: 193 // fallback, kernels older than 3.15 don't expose the mount id in this place
188 fprintf(stderr, "Error: cannot read %s\n", fdinfo); 194 fclose(fp);
189 exit(1); 195 close(fd);
196 free(fdinfo);
197 return -2;
190} 198}
191 199
192// Return array with all paths that might need a remount. 200// Return array with all paths that might need a remount.
@@ -208,7 +216,11 @@ char **build_mount_array(const int mountid, const char *path) {
208 // read /proc/self/mountinfo 216 // read /proc/self/mountinfo
209 size_t pathlen = strlen(path); 217 size_t pathlen = strlen(path);
210 int found = 0; 218 int found = 0;
211 while (fgets(mbuf, MAX_BUF, fp)) { 219 if (fgets(mbuf, MAX_BUF, fp) == NULL) {
220 fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n");
221 exit(1);
222 }
223 do {
212 // find mount point with mount id 224 // find mount point with mount id
213 if (!found) { 225 if (!found) {
214 parse_line(mbuf, &mdata); 226 parse_line(mbuf, &mdata);
@@ -230,7 +242,8 @@ char **build_mount_array(const int mountid, const char *path) {
230 else 242 else
231 continue; 243 continue;
232 } 244 }
233 // from here on add all mount points below path 245 // from here on add all mount points below path,
246 // don't remount blacklisted paths
234 parse_line(mbuf, &mdata); 247 parse_line(mbuf, &mdata);
235 if (strncmp(mdata.dir, path, pathlen) == 0 && 248 if (strncmp(mdata.dir, path, pathlen) == 0 &&
236 mdata.dir[pathlen] == '/' && 249 mdata.dir[pathlen] == '/' &&
@@ -248,7 +261,8 @@ char **build_mount_array(const int mountid, const char *path) {
248 errExit("strdup"); 261 errExit("strdup");
249 cnt++; 262 cnt++;
250 } 263 }
251 } 264 } while (fgets(mbuf, MAX_BUF, fp));
265
252 if (cnt == size) { 266 if (cnt == size) {
253 size++; 267 size++;
254 rv = realloc(rv, size * sizeof(*rv)); 268 rv = realloc(rv, size * sizeof(*rv));