diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/fs_home.c | 1 | ||||
-rw-r--r-- | src/firejail/fs_whitelist.c | 40 | ||||
-rw-r--r-- | src/firejail/usage.c | 1 | ||||
-rw-r--r-- | src/firejail/x11.c | 19 | ||||
-rw-r--r-- | src/man/firejail.txt | 8 | ||||
-rw-r--r-- | src/profstats/main.c | 24 |
6 files changed, 79 insertions, 14 deletions
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index bec22e5a6..dbc74bfff 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
22 | #include <linux/limits.h> | 22 | #include <linux/limits.h> |
23 | #include <glob.h> | ||
24 | #include <dirent.h> | 23 | #include <dirent.h> |
25 | #include <errno.h> | 24 | #include <errno.h> |
26 | #include <sys/stat.h> | 25 | #include <sys/stat.h> |
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c index c5b066b12..3f3075570 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c | |||
@@ -346,6 +346,39 @@ static void whitelist_home(int topdir) { | |||
346 | } | 346 | } |
347 | 347 | ||
348 | 348 | ||
349 | static void globbing(const char *pattern) { | ||
350 | assert(pattern); | ||
351 | |||
352 | // globbing | ||
353 | glob_t globbuf; | ||
354 | int globerr = glob(pattern, GLOB_NOCHECK | GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf); | ||
355 | if (globerr) { | ||
356 | fprintf(stderr, "Error: failed to glob private-bin pattern %s\n", pattern); | ||
357 | exit(1); | ||
358 | } | ||
359 | |||
360 | size_t i; | ||
361 | for (i = 0; i < globbuf.gl_pathc; i++) { | ||
362 | assert(globbuf.gl_pathv[i]); | ||
363 | // testing for GLOB_NOCHECK - no pattern matched returns the original pattern | ||
364 | if (strcmp(globbuf.gl_pathv[i], pattern) == 0) | ||
365 | continue; | ||
366 | |||
367 | // build the new profile command | ||
368 | char *newcmd; | ||
369 | if (asprintf(&newcmd, "whitelist %s", globbuf.gl_pathv[i]) == -1) | ||
370 | errExit("asprintf"); | ||
371 | |||
372 | // add the new profile command at the end of the list | ||
373 | if (arg_debug || arg_debug_whitelists) | ||
374 | printf("Adding new profile command: %s\n", newcmd); | ||
375 | profile_add(newcmd); | ||
376 | } | ||
377 | |||
378 | globfree(&globbuf); | ||
379 | } | ||
380 | |||
381 | |||
349 | void fs_whitelist(void) { | 382 | void fs_whitelist(void) { |
350 | ProfileEntry *entry = cfg.profile; | 383 | ProfileEntry *entry = cfg.profile; |
351 | if (!entry) | 384 | if (!entry) |
@@ -444,6 +477,13 @@ void fs_whitelist(void) { | |||
444 | else | 477 | else |
445 | fname = realpath(new_name, NULL); | 478 | fname = realpath(new_name, NULL); |
446 | 479 | ||
480 | // if this is not a real path, let's try globbing | ||
481 | // mark this entry as EMPTY_STRING and push the new paths at the end of profile entry list | ||
482 | // the new profile entries will be processed in this loop | ||
483 | // currently there is no globbing support for nowhitelist | ||
484 | if (!fname && !nowhitelist_flag) | ||
485 | globbing(new_name); | ||
486 | |||
447 | if (!fname) { | 487 | if (!fname) { |
448 | // file not found, blank the entry in the list and continue | 488 | // file not found, blank the entry in the list and continue |
449 | if (arg_debug || arg_debug_whitelists) { | 489 | if (arg_debug || arg_debug_whitelists) { |
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index c98ad3620..77bfea8c6 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -208,6 +208,7 @@ static char *usage_str = | |||
208 | "\twhitelist the syscalls specified by the command.\n" | 208 | "\twhitelist the syscalls specified by the command.\n" |
209 | " --seccomp.print=name|pid - print the seccomp filter for the sandbox\n" | 209 | " --seccomp.print=name|pid - print the seccomp filter for the sandbox\n" |
210 | "\tidentified by name or PID.\n" | 210 | "\tidentified by name or PID.\n" |
211 | " --seccomp.32[.drop,.keep][=syscall] - like above but for 32 bit architecture.\n" | ||
211 | #endif | 212 | #endif |
212 | " --shell=none - run the program directly without a user shell.\n" | 213 | " --shell=none - run the program directly without a user shell.\n" |
213 | " --shell=program - set default user shell.\n" | 214 | " --shell=program - set default user shell.\n" |
diff --git a/src/firejail/x11.c b/src/firejail/x11.c index 74de24b47..98ac184d9 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c | |||
@@ -1235,16 +1235,15 @@ void x11_xorg(void) { | |||
1235 | 1235 | ||
1236 | // move the temporary file in RUN_XAUTHORITY_SEC_FILE in order to have it deleted | 1236 | // move the temporary file in RUN_XAUTHORITY_SEC_FILE in order to have it deleted |
1237 | // automatically when the sandbox is closed (rename doesn't work) | 1237 | // automatically when the sandbox is closed (rename doesn't work) |
1238 | // root needed | 1238 | if (arg_debug) |
1239 | if (copy_file(tmpfname, RUN_XAUTHORITY_SEC_FILE, getuid(), getgid(), 0600)) { | 1239 | printf("Copying the new .Xauthority file\n"); |
1240 | fprintf(stderr, "Error: cannot create the new .Xauthority file\n"); | 1240 | copy_file_from_user_to_root(tmpfname, RUN_XAUTHORITY_SEC_FILE, getuid(), getgid(), 0600); |
1241 | exit(1); | 1241 | |
1242 | } | ||
1243 | /* coverity[toctou] */ | 1242 | /* coverity[toctou] */ |
1244 | unlink(tmpfname); | 1243 | unlink(tmpfname); |
1245 | umount("/tmp"); | 1244 | umount("/tmp"); |
1246 | 1245 | ||
1247 | // remount RUN_XAUTHORITY_SEC_FILE noexec, nodev, nosuid | 1246 | // mount RUN_XAUTHORITY_SEC_FILE noexec, nodev, nosuid |
1248 | fs_remount(RUN_XAUTHORITY_SEC_FILE, MOUNT_NOEXEC, 0); | 1247 | fs_remount(RUN_XAUTHORITY_SEC_FILE, MOUNT_NOEXEC, 0); |
1249 | 1248 | ||
1250 | // Ensure there is already a file in the usual location, so that bind-mount below will work. | 1249 | // Ensure there is already a file in the usual location, so that bind-mount below will work. |
@@ -1354,19 +1353,17 @@ void fs_x11(void) { | |||
1354 | if (mount("/tmp/.X11-unix", RUN_WHITELIST_X11_DIR, 0, MS_BIND|MS_REC, 0) < 0) | 1353 | if (mount("/tmp/.X11-unix", RUN_WHITELIST_X11_DIR, 0, MS_BIND|MS_REC, 0) < 0) |
1355 | errExit("mount bind"); | 1354 | errExit("mount bind"); |
1356 | 1355 | ||
1357 | // This directory must be mode 1777, or Xlib will barf. | 1356 | // This directory must be mode 1777 |
1358 | if (mount("tmpfs", "/tmp/.X11-unix", "tmpfs", | 1357 | if (mount("tmpfs", "/tmp/.X11-unix", "tmpfs", |
1359 | MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME, | 1358 | MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME, |
1360 | "mode=1777,uid=0,gid=0") < 0) | 1359 | "mode=1777,uid=0,gid=0") < 0) |
1361 | errExit("mounting tmpfs on /tmp/.X11-unix"); | 1360 | errExit("mounting tmpfs on /tmp/.X11-unix"); |
1362 | fs_logger("tmpfs /tmp/.X11-unix"); | 1361 | fs_logger("tmpfs /tmp/.X11-unix"); |
1363 | 1362 | ||
1364 | // create an empty file which will have the desired socket bind-mounted over it | 1363 | // create an empty root-owned file which will have the desired socket bind-mounted over it |
1365 | int fd = open(x11file, O_RDWR|O_CREAT|O_EXCL, x11stat.st_mode & ~S_IFMT); | 1364 | int fd = open(x11file, O_RDONLY|O_CREAT|O_EXCL, S_IRUSR | S_IWUSR); |
1366 | if (fd < 0) | 1365 | if (fd < 0) |
1367 | errExit(x11file); | 1366 | errExit(x11file); |
1368 | if (fchown(fd, x11stat.st_uid, x11stat.st_gid)) | ||
1369 | errExit("fchown"); | ||
1370 | close(fd); | 1367 | close(fd); |
1371 | 1368 | ||
1372 | // the mount source is under control of the user, so be careful and | 1369 | // the mount source is under control of the user, so be careful and |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 13dcf09ee..1bed40015 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -2346,6 +2346,10 @@ the same top directory. For user home, both the link and the real file should be | |||
2346 | .br | 2346 | .br |
2347 | 2347 | ||
2348 | .br | 2348 | .br |
2349 | File globbing is supported, see \fBFILE GLOBBING\fR section for more details. | ||
2350 | .br | ||
2351 | |||
2352 | .br | ||
2349 | Example: | 2353 | Example: |
2350 | .br | 2354 | .br |
2351 | $ firejail \-\-noprofile \-\-whitelist=~/.mozilla | 2355 | $ firejail \-\-noprofile \-\-whitelist=~/.mozilla |
@@ -2353,6 +2357,8 @@ $ firejail \-\-noprofile \-\-whitelist=~/.mozilla | |||
2353 | $ firejail \-\-whitelist=/tmp/.X11-unix --whitelist=/dev/null | 2357 | $ firejail \-\-whitelist=/tmp/.X11-unix --whitelist=/dev/null |
2354 | .br | 2358 | .br |
2355 | $ firejail "\-\-whitelist=/home/username/My Virtual Machines" | 2359 | $ firejail "\-\-whitelist=/home/username/My Virtual Machines" |
2360 | .br | ||
2361 | $ firejail \-\-whitelist=~/work* \-\-whitelist=/var/backups* | ||
2356 | 2362 | ||
2357 | .TP | 2363 | .TP |
2358 | \fB\-\-writable-etc | 2364 | \fB\-\-writable-etc |
@@ -2722,7 +2728,7 @@ The globbing feature is implemented using glibc glob command. For more informati | |||
2722 | 2728 | ||
2723 | .br | 2729 | .br |
2724 | .TP | 2730 | .TP |
2725 | The following command line options are supported: \-\-blacklist, \-\-private-bin, \-\-noexec, \-\-read-only, \-\-read-write, and \-\-tmpfs. | 2731 | The following command line options are supported: \-\-blacklist, \-\-private-bin, \-\-noexec, \-\-read-only, \-\-read-write, \-\-tmpfs, and \-\-whitelist. |
2726 | .br | 2732 | .br |
2727 | 2733 | ||
2728 | .br | 2734 | .br |
diff --git a/src/profstats/main.c b/src/profstats/main.c index 76b90f01b..f8818982f 100644 --- a/src/profstats/main.c +++ b/src/profstats/main.c | |||
@@ -35,6 +35,8 @@ static int cnt_noexec = 0; // include disable-exec.inc | |||
35 | static int cnt_privatedev = 0; | 35 | static int cnt_privatedev = 0; |
36 | static int cnt_privatetmp = 0; | 36 | static int cnt_privatetmp = 0; |
37 | static int cnt_whitelistvar = 0; // include whitelist-var-common.inc | 37 | static int cnt_whitelistvar = 0; // include whitelist-var-common.inc |
38 | static int cnt_whitelistrunuser = 0; // include whitelist-runuser-common.inc | ||
39 | static int cnt_whitelistusrshare = 0; // include whitelist-usr-share-common.inc | ||
38 | static int cnt_ssh = 0; | 40 | static int cnt_ssh = 0; |
39 | 41 | ||
40 | static int level = 0; | 42 | static int level = 0; |
@@ -46,6 +48,8 @@ static int arg_noexec = 0; | |||
46 | static int arg_privatedev = 0; | 48 | static int arg_privatedev = 0; |
47 | static int arg_privatetmp = 0; | 49 | static int arg_privatetmp = 0; |
48 | static int arg_whitelistvar = 0; | 50 | static int arg_whitelistvar = 0; |
51 | static int arg_whitelistrunuser = 0; | ||
52 | static int arg_whitelistusrshare = 0; | ||
49 | static int arg_ssh = 0; | 53 | static int arg_ssh = 0; |
50 | 54 | ||
51 | static char *profile = NULL; | 55 | static char *profile = NULL; |
@@ -63,6 +67,8 @@ static void usage(void) { | |||
63 | printf(" --private-tmp - print profiles without private-tmp\n"); | 67 | printf(" --private-tmp - print profiles without private-tmp\n"); |
64 | printf(" --seccomp - print profiles without seccomp\n"); | 68 | printf(" --seccomp - print profiles without seccomp\n"); |
65 | printf(" --whitelist-var - print profiles without \"include whitelist-var-common.inc\"\n"); | 69 | printf(" --whitelist-var - print profiles without \"include whitelist-var-common.inc\"\n"); |
70 | printf(" --whitelist-runuser - print profiles without \"include whitelist-runuser-common.inc\"\n"); | ||
71 | printf(" --whitelist-usrshare - print profiles without \"include whitelist-usr-share-common.inc\"\n"); | ||
66 | printf(" --debug\n"); | 72 | printf(" --debug\n"); |
67 | printf("\n"); | 73 | printf("\n"); |
68 | } | 74 | } |
@@ -102,6 +108,10 @@ void process_file(const char *fname) { | |||
102 | cnt_noexec++; | 108 | cnt_noexec++; |
103 | else if (strncmp(ptr, "include whitelist-var-common.inc", 32) == 0) | 109 | else if (strncmp(ptr, "include whitelist-var-common.inc", 32) == 0) |
104 | cnt_whitelistvar++; | 110 | cnt_whitelistvar++; |
111 | else if (strncmp(ptr, "include whitelist-runuser-common.inc", 32) == 0) | ||
112 | cnt_whitelistrunuser++; | ||
113 | else if (strncmp(ptr, "include whitelist-usr-share-common.inc", 32) == 0) | ||
114 | cnt_whitelistusrshare++; | ||
105 | else if (strncmp(ptr, "include disable-common.inc", 26) == 0) | 115 | else if (strncmp(ptr, "include disable-common.inc", 26) == 0) |
106 | cnt_ssh++; | 116 | cnt_ssh++; |
107 | else if (strncmp(ptr, "net none", 8) == 0) | 117 | else if (strncmp(ptr, "net none", 8) == 0) |
@@ -159,6 +169,10 @@ int main(int argc, char **argv) { | |||
159 | arg_privatetmp = 1; | 169 | arg_privatetmp = 1; |
160 | else if (strcmp(argv[i], "--whitelist-var") == 0) | 170 | else if (strcmp(argv[i], "--whitelist-var") == 0) |
161 | arg_whitelistvar = 1; | 171 | arg_whitelistvar = 1; |
172 | else if (strcmp(argv[i], "--whitelist-runuser") == 0) | ||
173 | arg_whitelistrunuser = 1; | ||
174 | else if (strcmp(argv[i], "--whitelist-usrshare") == 0) | ||
175 | arg_whitelistusrshare = 1; | ||
162 | else if (strcmp(argv[i], "--ssh") == 0) | 176 | else if (strcmp(argv[i], "--ssh") == 0) |
163 | arg_ssh = 1; | 177 | arg_ssh = 1; |
164 | else if (*argv[i] == '-') { | 178 | else if (*argv[i] == '-') { |
@@ -188,6 +202,8 @@ int main(int argc, char **argv) { | |||
188 | int dotlocal = cnt_dotlocal; | 202 | int dotlocal = cnt_dotlocal; |
189 | int globalsdotlocal = cnt_globalsdotlocal; | 203 | int globalsdotlocal = cnt_globalsdotlocal; |
190 | int whitelistvar = cnt_whitelistvar; | 204 | int whitelistvar = cnt_whitelistvar; |
205 | int whitelistrunuser = cnt_whitelistrunuser; | ||
206 | int whitelistusrshare = cnt_whitelistusrshare; | ||
191 | int ssh = cnt_ssh; | 207 | int ssh = cnt_ssh; |
192 | 208 | ||
193 | // process file | 209 | // process file |
@@ -220,6 +236,10 @@ int main(int argc, char **argv) { | |||
220 | printf("No private-tmp found in %s\n", argv[i]); | 236 | printf("No private-tmp found in %s\n", argv[i]); |
221 | if (arg_whitelistvar && whitelistvar == cnt_whitelistvar) | 237 | if (arg_whitelistvar && whitelistvar == cnt_whitelistvar) |
222 | printf("No include whitelist-var-common.inc found in %s\n", argv[i]); | 238 | printf("No include whitelist-var-common.inc found in %s\n", argv[i]); |
239 | if (arg_whitelistrunuser && whitelistrunuser == cnt_whitelistrunuser) | ||
240 | printf("No include whitelist-runuser-common.inc found in %s\n", argv[i]); | ||
241 | if (arg_whitelistusrshare && whitelistusrshare == cnt_whitelistusrshare) | ||
242 | printf("No include whitelist-usr-share-common.inc found in %s\n", argv[i]); | ||
223 | if (arg_ssh && ssh == cnt_ssh) | 243 | if (arg_ssh && ssh == cnt_ssh) |
224 | printf("No include disable-common.inc found in %s\n", argv[i]); | 244 | printf("No include disable-common.inc found in %s\n", argv[i]); |
225 | 245 | ||
@@ -238,7 +258,9 @@ int main(int argc, char **argv) { | |||
238 | printf(" apparmor\t\t\t%d\n", cnt_apparmor); | 258 | printf(" apparmor\t\t\t%d\n", cnt_apparmor); |
239 | printf(" private-dev\t\t\t%d\n", cnt_privatedev); | 259 | printf(" private-dev\t\t\t%d\n", cnt_privatedev); |
240 | printf(" private-tmp\t\t\t%d\n", cnt_privatetmp); | 260 | printf(" private-tmp\t\t\t%d\n", cnt_privatetmp); |
241 | printf(" whitelist var directory\t%d (include whitelist-var-common.inc)\n", cnt_whitelistvar); | 261 | printf(" whitelist var\t\t%d (include whitelist-var-common.inc)\n", cnt_whitelistvar); |
262 | printf(" whitelist run/user\t\t%d (include whitelist-runuser-common.inc)\n", cnt_whitelistrunuser); | ||
263 | printf(" whitelist usr/share\t\t%d (include whitelist-usr-share-common.inc)\n", cnt_whitelistusrshare); | ||
242 | printf(" net none\t\t\t%d\n", cnt_netnone); | 264 | printf(" net none\t\t\t%d\n", cnt_netnone); |
243 | printf("\n"); | 265 | printf("\n"); |
244 | return 0; | 266 | return 0; |