aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fbuilder/build_fs.c3
-rw-r--r--src/firejail/firejail.h3
-rw-r--r--src/firejail/fs.c11
-rw-r--r--src/firejail/main.c4
-rw-r--r--src/firejail/mountinfo.c149
-rw-r--r--src/firejail/profile.c5
-rw-r--r--src/firejail/util.c74
-rw-r--r--src/man/firejail.txt14
8 files changed, 133 insertions, 130 deletions
diff --git a/src/fbuilder/build_fs.c b/src/fbuilder/build_fs.c
index 8700e0ba1..a1847284c 100644
--- a/src/fbuilder/build_fs.c
+++ b/src/fbuilder/build_fs.c
@@ -236,9 +236,6 @@ void build_share(const char *fname, FILE *fp) {
236//******************************************* 236//*******************************************
237static FileDB *tmp_out = NULL; 237static FileDB *tmp_out = NULL;
238static void tmp_callback(char *ptr) { 238static void tmp_callback(char *ptr) {
239 // skip strace file
240 if (strncmp(ptr, "/tmp/firejail-strace", 20) == 0)
241 return;
242 if (strncmp(ptr, "/tmp/runtime-", 13) == 0) 239 if (strncmp(ptr, "/tmp/runtime-", 13) == 0)
243 return; 240 return;
244 if (strcmp(ptr, "/tmp") == 0) 241 if (strcmp(ptr, "/tmp") == 0)
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 5bebec185..a6924b830 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -519,6 +519,7 @@ void touch_file_as_user(const char *fname, mode_t mode);
519int is_dir(const char *fname); 519int is_dir(const char *fname);
520int is_link(const char *fname); 520int is_link(const char *fname);
521char *realpath_as_user(const char *fname); 521char *realpath_as_user(const char *fname);
522ssize_t readlink_as_user(const char *fname, char *buf, size_t sz);
522int stat_as_user(const char *fname, struct stat *s); 523int stat_as_user(const char *fname, struct stat *s);
523int lstat_as_user(const char *fname, struct stat *s); 524int lstat_as_user(const char *fname, struct stat *s);
524void trim_trailing_slash_or_dot(char *path); 525void trim_trailing_slash_or_dot(char *path);
@@ -566,7 +567,7 @@ typedef struct {
566// mountinfo.c 567// mountinfo.c
567MountData *get_last_mount(void); 568MountData *get_last_mount(void);
568int get_mount_id(int fd); 569int get_mount_id(int fd);
569char **build_mount_array(const int mount_id, const char *path); 570char **build_mount_array(const int mountid, const char *path);
570 571
571// fs_var.c 572// fs_var.c
572void fs_var_log(void); // mounting /var/log 573void 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/main.c b/src/firejail/main.c
index c5b3d5739..1ba70b0bd 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -2156,6 +2156,10 @@ int main(int argc, char **argv, char **envp) {
2156 arg_novideo = 1; 2156 arg_novideo = 1;
2157 else if (strcmp(argv[i], "--no3d") == 0) 2157 else if (strcmp(argv[i], "--no3d") == 0)
2158 arg_no3d = 1; 2158 arg_no3d = 1;
2159 else if (strcmp(argv[i], "--noprinters") == 0) {
2160 profile_add("blacklist /dev/lp*");
2161 profile_add("blacklist /run/cups/cups.sock");
2162 }
2159 else if (strcmp(argv[i], "--notv") == 0) 2163 else if (strcmp(argv[i], "--notv") == 0)
2160 arg_notv = 1; 2164 arg_notv = 1;
2161 else if (strcmp(argv[i], "--nodvd") == 0) 2165 else if (strcmp(argv[i], "--nodvd") == 0)
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
36static int read_oct(const char *path) { 36static 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
52static void unmangle_path(char *path) { 50static 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.
71static void parse_line(char *line, MountData *output) { 67static 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.
222char **build_mount_array(const int mount_id, const char *path) { 214char **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}
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 9d92b6199..babc3941e 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -449,6 +449,11 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
449 arg_no3d = 1; 449 arg_no3d = 1;
450 return 0; 450 return 0;
451 } 451 }
452 else if (strcmp(ptr, "noprinters") == 0) {
453 profile_add("blacklist /dev/lp*");
454 profile_add("blacklist /run/cups/cups.sock");
455 return 0;
456 }
452 else if (strcmp(ptr, "noinput") == 0) { 457 else if (strcmp(ptr, "noinput") == 0) {
453 arg_noinput = 1; 458 arg_noinput = 1;
454 return 0; 459 return 0;
diff --git a/src/firejail/util.c b/src/firejail/util.c
index 732e93134..55dcdc246 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -484,13 +484,6 @@ int is_link(const char *fname) {
484 if (*fname == '\0') 484 if (*fname == '\0')
485 return 0; 485 return 0;
486 486
487 int called_as_root = 0;
488 if (geteuid() == 0)
489 called_as_root = 1;
490
491 if (called_as_root)
492 EUID_USER();
493
494 // remove trailing '/' if any 487 // remove trailing '/' if any
495 char *tmp = strdup(fname); 488 char *tmp = strdup(fname);
496 if (!tmp) 489 if (!tmp)
@@ -498,12 +491,9 @@ int is_link(const char *fname) {
498 trim_trailing_slash_or_dot(tmp); 491 trim_trailing_slash_or_dot(tmp);
499 492
500 char c; 493 char c;
501 ssize_t rv = readlink(tmp, &c, 1); 494 ssize_t rv = readlink_as_user(tmp, &c, 1);
502 free(tmp); 495 free(tmp);
503 496
504 if (called_as_root)
505 EUID_ROOT();
506
507 return (rv != -1); 497 return (rv != -1);
508} 498}
509 499
@@ -525,6 +515,24 @@ char *realpath_as_user(const char *fname) {
525 return rv; 515 return rv;
526} 516}
527 517
518ssize_t readlink_as_user(const char *fname, char *buf, size_t sz) {
519 assert(fname && buf && sz);
520
521 int called_as_root = 0;
522 if (geteuid() == 0)
523 called_as_root = 1;
524
525 if (called_as_root)
526 EUID_USER();
527
528 ssize_t rv = readlink(fname, buf, sz);
529
530 if (called_as_root)
531 EUID_ROOT();
532
533 return rv;
534}
535
528int stat_as_user(const char *fname, struct stat *s) { 536int stat_as_user(const char *fname, struct stat *s) {
529 assert(fname); 537 assert(fname);
530 538
@@ -997,31 +1005,33 @@ int create_empty_dir_as_user(const char *dir, mode_t mode) {
997 assert(dir); 1005 assert(dir);
998 mode &= 07777; 1006 mode &= 07777;
999 1007
1000 if (access(dir, F_OK) != 0) { 1008 if (access(dir, F_OK) == 0)
1009 return 0;
1010
1011 pid_t child = fork();
1012 if (child < 0)
1013 errExit("fork");
1014 if (child == 0) {
1015 // drop privileges
1016 drop_privs(0);
1017
1001 if (arg_debug) 1018 if (arg_debug)
1002 printf("Creating empty %s directory\n", dir); 1019 printf("Creating empty %s directory\n", dir);
1003 pid_t child = fork(); 1020 if (mkdir(dir, mode) == 0) {
1004 if (child < 0) 1021 int err = chmod(dir, mode);
1005 errExit("fork"); 1022 (void) err;
1006 if (child == 0) { 1023 }
1007 // drop privileges 1024 else if (arg_debug)
1008 drop_privs(0); 1025 printf("Directory %s not created: %s\n", dir, strerror(errno));
1009
1010 if (mkdir(dir, mode) == 0) {
1011 int err = chmod(dir, mode);
1012 (void) err;
1013 }
1014 else if (arg_debug)
1015 printf("Directory %s not created: %s\n", dir, strerror(errno));
1016 1026
1017 __gcov_flush(); 1027 __gcov_flush();
1018 1028
1019 _exit(0); 1029 _exit(0);
1020 }
1021 waitpid(child, NULL, 0);
1022 if (access(dir, F_OK) == 0)
1023 return 1;
1024 } 1030 }
1031 waitpid(child, NULL, 0);
1032
1033 if (access(dir, F_OK) == 0)
1034 return 1;
1025 return 0; 1035 return 0;
1026} 1036}
1027 1037
@@ -1411,7 +1421,7 @@ static int has_link(const char *dir) {
1411void check_homedir(const char *dir) { 1421void check_homedir(const char *dir) {
1412 assert(dir); 1422 assert(dir);
1413 if (dir[0] != '/') { 1423 if (dir[0] != '/') {
1414 fprintf(stderr, "Error: invalid user directory \"%s\"\n", cfg.homedir); 1424 fprintf(stderr, "Error: invalid user directory \"%s\"\n", dir);
1415 exit(1); 1425 exit(1);
1416 } 1426 }
1417 // symlinks are rejected in many places 1427 // symlinks are rejected in many places
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 154def585..e724e4bb9 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -310,6 +310,11 @@ regular user, nonewprivs and a default capabilities filter are enabled.
310Example: 310Example:
311.br 311.br
312$ firejail \-\-chroot=/media/ubuntu warzone2100 312$ firejail \-\-chroot=/media/ubuntu warzone2100
313.br
314
315.br
316For automatic mounting of X11 and PulseAudio sockets set environment variables
317FIREJAIL_CHROOT_X11 and FIREJAIL_CHROOT_PULSE.
313#endif 318#endif
314.TP 319.TP
315\fB\-\-cpu=cpu-number,cpu-number,cpu-number 320\fB\-\-cpu=cpu-number,cpu-number,cpu-number
@@ -2192,6 +2197,11 @@ More information about groups can be found in /usr/share/doc/firejail/syscalls.t
2192.br 2197.br
2193 2198
2194.br 2199.br
2200The default list can be customized, see \-\-seccomp= for a description.
2201It can be customized also globally in /etc/firejail/firejail.config file.
2202.br
2203
2204.br
2195System architecture is strictly imposed only if flag 2205System architecture is strictly imposed only if flag
2196\-\-seccomp.block-secondary is used. The filter is applied at run time 2206\-\-seccomp.block-secondary is used. The filter is applied at run time
2197only if the correct architecture was detected. For the case of I386 2207only if the correct architecture was detected. For the case of I386
@@ -2206,11 +2216,7 @@ Firejail will print seccomp violations to the audit log if the kernel was compil
2206Example: 2216Example:
2207.br 2217.br
2208$ firejail \-\-seccomp 2218$ firejail \-\-seccomp
2209.br
2210 2219
2211.br
2212The default list can be customized, see \-\-seccomp= for a description. It can be customized
2213also globally in /etc/firejail/firejail.config file.
2214 2220
2215.TP 2221.TP
2216\fB\-\-seccomp=syscall,@group,!syscall2 2222\fB\-\-seccomp=syscall,@group,!syscall2