aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2021-10-06 23:10:37 +0200
committerLibravatar GitHub <noreply@github.com>2021-10-06 23:10:37 +0200
commitf02a218b52127923ea300d6f39a6f6c1516191f7 (patch)
treed7fe721feb6549c337816a59a2b139f9bf70a898
parentMerge pull request #4371 from chrpinedo/patch-1 (diff)
parentmountinfo: get mount id from failed call to name_to_handle_at (diff)
downloadfirejail-f02a218b52127923ea300d6f39a6f6c1516191f7.tar.gz
firejail-f02a218b52127923ea300d6f39a6f6c1516191f7.tar.zst
firejail-f02a218b52127923ea300d6f39a6f6c1516191f7.zip
Merge pull request #4590 from smitsohu/mountid
Read mount id also on legacy kernels
-rw-r--r--src/firejail/firejail.h2
-rw-r--r--src/firejail/fs.c38
-rw-r--r--src/firejail/mountinfo.c71
3 files changed, 63 insertions, 48 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 2a7d88575..e1ba8f48a 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -563,7 +563,7 @@ typedef struct {
563 563
564// mountinfo.c 564// mountinfo.c
565MountData *get_last_mount(void); 565MountData *get_last_mount(void);
566int get_mount_id(const char *path); 566int get_mount_id(int fd);
567char **build_mount_array(const int mount_id, const char *path); 567char **build_mount_array(const int mount_id, const char *path);
568 568
569// fs_var.c 569// fs_var.c
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index 6d01b5e5d..3144156a3 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -633,34 +633,30 @@ out:
633} 633}
634 634
635// remount recursively; requires a resolved path 635// remount recursively; requires a resolved path
636static void fs_remount_rec(const char *dir, OPERATION op) { 636static void fs_remount_rec(const char *path, OPERATION op) {
637 EUID_ASSERT(); 637 EUID_ASSERT();
638 assert(dir); 638 assert(op < OPERATION_MAX);
639 assert(path);
639 640
640 struct stat s; 641 // no need to search /proc/self/mountinfo for submounts if not a directory
641 if (stat(dir, &s) != 0) 642 int fd = open(path, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
642 return; 643 if (fd < 0) {
643 if (!S_ISDIR(s.st_mode)) { 644 fs_remount_simple(path, op);
644 // no need to search in /proc/self/mountinfo for submounts if not a directory
645 fs_remount_simple(dir, op);
646 return; 645 return;
647 } 646 }
648 // get mount point of the directory 647
649 int mountid = get_mount_id(dir); 648 // get mount id of the directory
650 if (mountid == -1) 649 int mountid = get_mount_id(fd);
651 return; 650 close(fd);
652 if (mountid == -2) { 651 if (mountid < 0) {
653 // falling back to a simple remount on old kernels 652 // falling back to a simple remount
654 static int mount_warning = 0; 653 fwarning("%s %s not applied recursively\n", opstr[op], path);
655 if (!mount_warning) { 654 fs_remount_simple(path, op);
656 fwarning("read-only, read-write and noexec options are not applied recursively\n");
657 mount_warning = 1;
658 }
659 fs_remount_simple(dir, op);
660 return; 655 return;
661 } 656 }
657
662 // build array with all mount points that need to get remounted 658 // build array with all mount points that need to get remounted
663 char **arr = build_mount_array(mountid, dir); 659 char **arr = build_mount_array(mountid, path);
664 assert(arr); 660 assert(arr);
665 // remount 661 // remount
666 char **tmp = arr; 662 char **tmp = arr;
diff --git a/src/firejail/mountinfo.c b/src/firejail/mountinfo.c
index 64a94bd84..304f80eee 100644
--- a/src/firejail/mountinfo.c
+++ b/src/firejail/mountinfo.c
@@ -19,6 +19,7 @@
19*/ 19*/
20 20
21#include "firejail.h" 21#include "firejail.h"
22#include <errno.h>
22 23
23#include <fcntl.h> 24#include <fcntl.h>
24#ifndef O_PATH 25#ifndef O_PATH
@@ -151,53 +152,71 @@ MountData *get_last_mount(void) {
151 return &mdata; 152 return &mdata;
152} 153}
153 154
154// Extract the mount id from /proc/self/fdinfo and return it. 155// Returns mount id, or -1 if fd refers to a procfs or sysfs file
155int get_mount_id(const char *path) { 156static int get_mount_id_from_handle(int fd) {
156 EUID_ASSERT(); 157 EUID_ASSERT();
157 assert(path);
158 158
159 int fd = open(path, O_PATH|O_CLOEXEC); 159 char *proc;
160 if (fd == -1) 160 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
161 return -1; 161 errExit("asprintf");
162 struct file_handle *fh = malloc(sizeof *fh);
163 if (!fh)
164 errExit("malloc");
165 fh->handle_bytes = 0;
166
167 int rv = -1;
168 int tmp;
169 if (name_to_handle_at(-1, proc, fh, &tmp, AT_SYMLINK_FOLLOW) != -1) {
170 fprintf(stderr, "Error: unexpected result from name_to_handle_at\n");
171 exit(1);
172 }
173 if (errno == EOVERFLOW && fh->handle_bytes)
174 rv = tmp;
175
176 free(proc);
177 free(fh);
178 return rv;
179}
180
181// Returns mount id, or -1 on kernels < 3.15
182static int get_mount_id_from_fdinfo(int fd) {
183 EUID_ASSERT();
184 int rv = -1;
162 185
163 char *fdinfo; 186 char *proc;
164 if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1) 187 if (asprintf(&proc, "/proc/self/fdinfo/%d", fd) == -1)
165 errExit("asprintf"); 188 errExit("asprintf");
166 EUID_ROOT(); 189 EUID_ROOT();
167 FILE *fp = fopen(fdinfo, "re"); 190 FILE *fp = fopen(proc, "re");
168 EUID_USER(); 191 EUID_USER();
169 free(fdinfo);
170 if (!fp) 192 if (!fp)
171 goto errexit; 193 goto errexit;
172 194
173 // read the file
174 char buf[MAX_BUF]; 195 char buf[MAX_BUF];
175 if (fgets(buf, MAX_BUF, fp) == NULL) 196 while (fgets(buf, MAX_BUF, fp)) {
176 goto errexit;
177 do {
178 if (strncmp(buf, "mnt_id:", 7) == 0) { 197 if (strncmp(buf, "mnt_id:", 7) == 0) {
179 char *ptr = buf + 7; 198 if (sscanf(buf + 7, "%d", &rv) != 1)
180 while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
181 ptr++;
182 }
183 if (*ptr == '\0')
184 goto errexit; 199 goto errexit;
185 fclose(fp); 200 break;
186 close(fd);
187 return atoi(ptr);
188 } 201 }
189 } while (fgets(buf, MAX_BUF, fp)); 202 }
190 203
191 // fallback, kernels older than 3.15 don't expose the mount id in this place 204 free(proc);
192 fclose(fp); 205 fclose(fp);
193 close(fd); 206 return rv;
194 return -2;
195 207
196errexit: 208errexit:
197 fprintf(stderr, "Error: cannot read proc file\n"); 209 fprintf(stderr, "Error: cannot read proc file\n");
198 exit(1); 210 exit(1);
199} 211}
200 212
213int get_mount_id(int fd) {
214 int rv = get_mount_id_from_fdinfo(fd);
215 if (rv < 0)
216 rv = get_mount_id_from_handle(fd);
217 return rv;
218}
219
201// Check /proc/self/mountinfo if path contains any mounts points. 220// Check /proc/self/mountinfo if path contains any mounts points.
202// Returns an array that can be iterated over for recursive remounting. 221// Returns an array that can be iterated over for recursive remounting.
203char **build_mount_array(const int mount_id, const char *path) { 222char **build_mount_array(const int mount_id, const char *path) {