diff options
author | 2021-10-18 18:01:46 +0200 | |
---|---|---|
committer | 2021-10-18 18:09:38 +0200 | |
commit | 316a1cd6227e259908287a768953b1171cd9477d (patch) | |
tree | b6aef72d5b6d5b3855fe69b6fd7b567ecd54a0d3 | |
parent | readability (diff) | |
download | firejail-316a1cd6227e259908287a768953b1171cd9477d.tar.gz firejail-316a1cd6227e259908287a768953b1171cd9477d.tar.zst firejail-316a1cd6227e259908287a768953b1171cd9477d.zip |
mountinfo: improve readability
Removes the inconsistency that some blacklisted
paths could be remounted (files specified explicitly)
and some could not. Now all blacklisted paths can
be mounted nosuid, nodev, noexec if users
specify this.
Also fixes the bug that mount id can indeed be 0.
Other than that no functional or algorithmic changes,
only readability improvements.
-rw-r--r-- | src/firejail/firejail.h | 2 | ||||
-rw-r--r-- | src/firejail/fs.c | 11 | ||||
-rw-r--r-- | src/firejail/mountinfo.c | 149 |
3 files changed, 71 insertions, 91 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 13b7b9523..a6924b830 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -567,7 +567,7 @@ typedef struct { | |||
567 | // mountinfo.c | 567 | // mountinfo.c |
568 | MountData *get_last_mount(void); | 568 | MountData *get_last_mount(void); |
569 | int get_mount_id(int fd); | 569 | int get_mount_id(int fd); |
570 | char **build_mount_array(const int mount_id, const char *path); | 570 | char **build_mount_array(const int mountid, const char *path); |
571 | 571 | ||
572 | // fs_var.c | 572 | // fs_var.c |
573 | void fs_var_log(void); // mounting /var/log | 573 | void fs_var_log(void); // mounting /var/log |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 0b9a38035..9c1b889ed 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -654,12 +654,13 @@ static void fs_remount_rec(const char *path, OPERATION op) { | |||
654 | 654 | ||
655 | // build array with all mount points that need to get remounted | 655 | // build array with all mount points that need to get remounted |
656 | char **arr = build_mount_array(mountid, path); | 656 | char **arr = build_mount_array(mountid, path); |
657 | assert(arr); | 657 | if (!arr) |
658 | return; | ||
658 | // remount | 659 | // remount |
659 | char **tmp = arr; | 660 | int i; |
660 | while (*tmp) { | 661 | for (i = 0; arr[i]; i++) { |
661 | fs_remount_simple(*tmp, op); | 662 | fs_remount_simple(arr[i], op); |
662 | free(*tmp++); | 663 | free(arr[i]); |
663 | } | 664 | } |
664 | free(arr); | 665 | free(arr); |
665 | } | 666 | } |
diff --git a/src/firejail/mountinfo.c b/src/firejail/mountinfo.c index 304f80eee..ee437e10b 100644 --- a/src/firejail/mountinfo.c +++ b/src/firejail/mountinfo.c | |||
@@ -33,43 +33,38 @@ static MountData mdata; | |||
33 | 33 | ||
34 | 34 | ||
35 | // Convert octal escape sequence to decimal value | 35 | // Convert octal escape sequence to decimal value |
36 | static int read_oct(const char *path) { | 36 | static unsigned read_oct(char *s) { |
37 | int dec = 0; | 37 | assert(s[0] == '\\'); |
38 | int digit, i; | 38 | s++; |
39 | // there are always exactly three octal digits | 39 | |
40 | for (i = 1; i < 4; i++) { | 40 | int i; |
41 | digit = *(path + i); | 41 | for (i = 0; i < 3; i++) |
42 | if (digit < '0' || digit > '7') { | 42 | assert(s[i] >= '0' && s[i] <= '7'); |
43 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | 43 | |
44 | exit(1); | 44 | return ((s[0] - '0') << 6 | |
45 | } | 45 | (s[1] - '0') << 3 | |
46 | dec = (dec << 3) + (digit - '0'); | 46 | (s[2] - '0') << 0); |
47 | } | ||
48 | return dec; | ||
49 | } | 47 | } |
50 | 48 | ||
51 | // Restore empty spaces in pathnames extracted from /proc/self/mountinfo | 49 | // Restore empty spaces in pathnames extracted from /proc/self/mountinfo |
52 | static void unmangle_path(char *path) { | 50 | static void unmangle_path(char *path) { |
53 | char *p = strchr(path, '\\'); | 51 | char *r = strchr(path, '\\'); |
54 | if (p && read_oct(p) == ' ') { | 52 | if (!r) |
55 | *p = ' '; | 53 | return; |
56 | int i = 3; | 54 | |
57 | do { | 55 | char *w = r; |
58 | p++; | 56 | do { |
59 | if (*(p + i) == '\\' && read_oct(p + i) == ' ') { | 57 | while (*r == '\\') { |
60 | *p = ' '; | 58 | *w++ = read_oct(r); |
61 | i += 3; | 59 | r += 4; |
62 | } | 60 | } |
63 | else | 61 | *w++ = *r; |
64 | *p = *(p + i); | 62 | } while (*r++); |
65 | } while (*p); | ||
66 | } | ||
67 | } | 63 | } |
68 | 64 | ||
69 | // Parse a line from /proc/self/mountinfo, | 65 | // Parse a line from /proc/self/mountinfo, |
70 | // the function does an exit(1) if anything goes wrong. | 66 | // the function does an exit(1) if anything goes wrong. |
71 | static void parse_line(char *line, MountData *output) { | 67 | static void parse_line(char *line, MountData *output) { |
72 | assert(line && output); | ||
73 | memset(output, 0, sizeof(*output)); | 68 | memset(output, 0, sizeof(*output)); |
74 | // extract mount id, filesystem name, directory and filesystem types | 69 | // extract mount id, filesystem name, directory and filesystem types |
75 | // examples: | 70 | // examples: |
@@ -87,8 +82,6 @@ static void parse_line(char *line, MountData *output) { | |||
87 | char *ptr = strtok(line, " "); | 82 | char *ptr = strtok(line, " "); |
88 | if (!ptr) | 83 | if (!ptr) |
89 | goto errexit; | 84 | goto errexit; |
90 | if (ptr != line) | ||
91 | goto errexit; | ||
92 | output->mountid = atoi(ptr); | 85 | output->mountid = atoi(ptr); |
93 | int cnt = 1; | 86 | int cnt = 1; |
94 | 87 | ||
@@ -109,10 +102,9 @@ static void parse_line(char *line, MountData *output) { | |||
109 | ptr = strtok(NULL, " "); | 102 | ptr = strtok(NULL, " "); |
110 | if (!ptr) | 103 | if (!ptr) |
111 | goto errexit; | 104 | goto errexit; |
112 | output->fstype = ptr++; | 105 | output->fstype = ptr; |
113 | 106 | ||
114 | 107 | if (output->mountid < 0 || | |
115 | if (output->mountid == 0 || | ||
116 | output->fsname == NULL || | 108 | output->fsname == NULL || |
117 | output->dir == NULL || | 109 | output->dir == NULL || |
118 | output->fstype == NULL) | 110 | output->fstype == NULL) |
@@ -195,9 +187,9 @@ static int get_mount_id_from_fdinfo(int fd) { | |||
195 | char buf[MAX_BUF]; | 187 | char buf[MAX_BUF]; |
196 | while (fgets(buf, MAX_BUF, fp)) { | 188 | while (fgets(buf, MAX_BUF, fp)) { |
197 | if (strncmp(buf, "mnt_id:", 7) == 0) { | 189 | if (strncmp(buf, "mnt_id:", 7) == 0) { |
198 | if (sscanf(buf + 7, "%d", &rv) != 1) | 190 | if (sscanf(buf + 7, "%d", &rv) == 1) |
199 | goto errexit; | 191 | break; |
200 | break; | 192 | goto errexit; |
201 | } | 193 | } |
202 | } | 194 | } |
203 | 195 | ||
@@ -219,62 +211,50 @@ int get_mount_id(int fd) { | |||
219 | 211 | ||
220 | // Check /proc/self/mountinfo if path contains any mounts points. | 212 | // Check /proc/self/mountinfo if path contains any mounts points. |
221 | // Returns an array that can be iterated over for recursive remounting. | 213 | // Returns an array that can be iterated over for recursive remounting. |
222 | char **build_mount_array(const int mount_id, const char *path) { | 214 | char **build_mount_array(const int mountid, const char *path) { |
223 | assert(path); | 215 | assert(path); |
224 | 216 | ||
225 | // open /proc/self/mountinfo | ||
226 | FILE *fp = fopen("/proc/self/mountinfo", "re"); | 217 | FILE *fp = fopen("/proc/self/mountinfo", "re"); |
227 | if (!fp) { | 218 | if (!fp) { |
228 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | 219 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); |
229 | exit(1); | 220 | exit(1); |
230 | } | 221 | } |
231 | 222 | ||
232 | // array to be returned | 223 | // try to find line with mount id |
233 | size_t cnt = 0; | 224 | int found = 0; |
225 | MountData mntp; | ||
226 | char line[MAX_BUF]; | ||
227 | while (fgets(line, MAX_BUF, fp)) { | ||
228 | parse_line(line, &mntp); | ||
229 | if (mntp.mountid == mountid) { | ||
230 | found = 1; | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | if (!found) { | ||
236 | fclose(fp); | ||
237 | return NULL; | ||
238 | } | ||
239 | |||
240 | // allocate array | ||
234 | size_t size = 32; | 241 | size_t size = 32; |
235 | char **rv = malloc(size * sizeof(*rv)); | 242 | char **rv = malloc(size * sizeof(*rv)); |
236 | if (!rv) | 243 | if (!rv) |
237 | errExit("malloc"); | 244 | errExit("malloc"); |
238 | 245 | ||
239 | // read /proc/self/mountinfo | 246 | // add directory itself |
240 | size_t pathlen = strlen(path); | 247 | size_t cnt = 0; |
241 | char buf[MAX_BUF]; | 248 | rv[cnt] = strdup(path); |
242 | MountData mntp; | 249 | if (rv[cnt] == NULL) |
243 | int found = 0; | 250 | errExit("strdup"); |
244 | 251 | ||
245 | if (fgets(buf, MAX_BUF, fp) == NULL) { | 252 | // and add all following mountpoints contained in this directory |
246 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | 253 | size_t pathlen = strlen(path); |
247 | exit(1); | 254 | while (fgets(line, MAX_BUF, fp)) { |
248 | } | 255 | parse_line(line, &mntp); |
249 | do { | 256 | if (strncmp(mntp.dir, path, pathlen) == 0 && mntp.dir[pathlen] == '/') { |
250 | parse_line(buf, &mntp); | 257 | if (++cnt == size) { |
251 | // find mount point with mount id | ||
252 | if (!found) { | ||
253 | if (mntp.mountid == mount_id) { | ||
254 | // give up if mount id has been reassigned, | ||
255 | // don't remount blacklisted path | ||
256 | if (strncmp(mntp.dir, path, strlen(mntp.dir)) || | ||
257 | strstr(mntp.fsname, "firejail.ro.dir") || | ||
258 | strstr(mntp.fsname, "firejail.ro.file")) | ||
259 | break; | ||
260 | |||
261 | rv[cnt] = strdup(path); | ||
262 | if (rv[cnt] == NULL) | ||
263 | errExit("strdup"); | ||
264 | cnt++; | ||
265 | found = 1; | ||
266 | continue; | ||
267 | } | ||
268 | continue; | ||
269 | } | ||
270 | // from here on add all mount points below path, | ||
271 | // don't remount blacklisted paths | ||
272 | if (strncmp(mntp.dir, path, pathlen) == 0 && | ||
273 | mntp.dir[pathlen] == '/' && | ||
274 | strstr(mntp.fsname, "firejail.ro.dir") == NULL && | ||
275 | strstr(mntp.fsname, "firejail.ro.file") == NULL) { | ||
276 | |||
277 | if (cnt == size) { | ||
278 | size *= 2; | 258 | size *= 2; |
279 | rv = realloc(rv, size * sizeof(*rv)); | 259 | rv = realloc(rv, size * sizeof(*rv)); |
280 | if (!rv) | 260 | if (!rv) |
@@ -283,18 +263,17 @@ char **build_mount_array(const int mount_id, const char *path) { | |||
283 | rv[cnt] = strdup(mntp.dir); | 263 | rv[cnt] = strdup(mntp.dir); |
284 | if (rv[cnt] == NULL) | 264 | if (rv[cnt] == NULL) |
285 | errExit("strdup"); | 265 | errExit("strdup"); |
286 | cnt++; | ||
287 | } | 266 | } |
288 | } while (fgets(buf, MAX_BUF, fp)); | 267 | } |
268 | fclose(fp); | ||
289 | 269 | ||
290 | if (cnt == size) { | 270 | // end of array |
291 | size++; | 271 | if (++cnt == size) { |
272 | ++size; | ||
292 | rv = realloc(rv, size * sizeof(*rv)); | 273 | rv = realloc(rv, size * sizeof(*rv)); |
293 | if (!rv) | 274 | if (!rv) |
294 | errExit("realloc"); | 275 | errExit("realloc"); |
295 | } | 276 | } |
296 | rv[cnt] = NULL; // end of the array | 277 | rv[cnt] = NULL; |
297 | |||
298 | fclose(fp); | ||
299 | return rv; | 278 | return rv; |
300 | } | 279 | } |