diff options
35 files changed, 468 insertions, 108 deletions
@@ -571,6 +571,8 @@ kortewegdevries (https://github.com/kortewegdevries) | |||
571 | - whitelisting evolution, kmail | 571 | - whitelisting evolution, kmail |
572 | Kristóf Marussy (https://github.com/kris7t) | 572 | Kristóf Marussy (https://github.com/kris7t) |
573 | - dns support | 573 | - dns support |
574 | kuesji koesnu (https://github.com/kuesji) | ||
575 | - unit suffixes for rlimit-fsize and rlimit-as | ||
574 | Kunal Mehta (https://github.com/legoktm) | 576 | Kunal Mehta (https://github.com/legoktm) |
575 | - converted all links to https in manpages | 577 | - converted all links to https in manpages |
576 | laniakea64 (https://github.com/laniakea64) | 578 | laniakea64 (https://github.com/laniakea64) |
@@ -1,6 +1,10 @@ | |||
1 | firejail (0.9.65) baseline; urgency=low | 1 | firejail (0.9.65) baseline; urgency=low |
2 | * deprecated --audit options, relpaced by jailcheck utility | 2 | * deprecated --audit options, relpaced by jailcheck utility |
3 | * deprecated follow-symlink-as-user from firejail.config | 3 | * deprecated follow-symlink-as-user from firejail.config |
4 | * new firejail.config settings: private-bin, private-etc | ||
5 | * new firejail.config settings: private-opt, private-srv | ||
6 | * new firejail.config settings: whitelist-disable-topdir | ||
7 | * new firejail.config settings: seccomp-filter-add | ||
4 | * rename --noautopulse to keep-config-pulse | 8 | * rename --noautopulse to keep-config-pulse |
5 | * filtering environment variables | 9 | * filtering environment variables |
6 | * zsh completion | 10 | * zsh completion |
diff --git a/etc/firejail.config b/etc/firejail.config index f5b3d5efa..43db49422 100644 --- a/etc/firejail.config +++ b/etc/firejail.config | |||
@@ -113,6 +113,10 @@ | |||
113 | # Enable or disable seccomp support, default enabled. | 113 | # Enable or disable seccomp support, default enabled. |
114 | # seccomp yes | 114 | # seccomp yes |
115 | 115 | ||
116 | # Add rules to the default seccomp filter. Same syntax as for --seccomp= | ||
117 | # None by default; this is an example. | ||
118 | # seccomp-filter-add !chroot,kcmp,mincore | ||
119 | |||
116 | # Seccomp error action, kill, log or errno (EPERM, ENOSYS etc) | 120 | # Seccomp error action, kill, log or errno (EPERM, ENOSYS etc) |
117 | # seccomp-error-action EPERM | 121 | # seccomp-error-action EPERM |
118 | 122 | ||
diff --git a/etc/inc/disable-programs.inc b/etc/inc/disable-programs.inc index 6fb62e017..0e575e5eb 100644 --- a/etc/inc/disable-programs.inc +++ b/etc/inc/disable-programs.inc | |||
@@ -39,6 +39,8 @@ blacklist ${HOME}/.WebStorm* | |||
39 | blacklist ${HOME}/.Wolfram Research | 39 | blacklist ${HOME}/.Wolfram Research |
40 | blacklist ${HOME}/.ZAP | 40 | blacklist ${HOME}/.ZAP |
41 | blacklist ${HOME}/.abook | 41 | blacklist ${HOME}/.abook |
42 | blacklist ${HOME}/.addressbook | ||
43 | blacklist ${HOME}/.alpine-smime | ||
42 | blacklist ${HOME}/.aMule | 44 | blacklist ${HOME}/.aMule |
43 | blacklist ${HOME}/.android | 45 | blacklist ${HOME}/.android |
44 | blacklist ${HOME}/.anydesk | 46 | blacklist ${HOME}/.anydesk |
@@ -831,6 +833,14 @@ blacklist ${HOME}/.paradoxinteractive | |||
831 | blacklist ${HOME}/.parallelrealities/blobwars | 833 | blacklist ${HOME}/.parallelrealities/blobwars |
832 | blacklist ${HOME}/.pcsxr | 834 | blacklist ${HOME}/.pcsxr |
833 | blacklist ${HOME}/.penguin-command | 835 | blacklist ${HOME}/.penguin-command |
836 | blacklist ${HOME}/.pine-crash | ||
837 | blacklist ${HOME}/.pine-debug1 | ||
838 | blacklist ${HOME}/.pine-debug2 | ||
839 | blacklist ${HOME}/.pine-debug3 | ||
840 | blacklist ${HOME}/.pine-debug4 | ||
841 | blacklist ${HOME}/.pine-interrupted-mail | ||
842 | blacklist ${HOME}/.pinerc | ||
843 | blacklist ${HOME}/.pinercex | ||
834 | blacklist ${HOME}/.pingus | 844 | blacklist ${HOME}/.pingus |
835 | blacklist ${HOME}/.pioneer | 845 | blacklist ${HOME}/.pioneer |
836 | blacklist ${HOME}/.purple | 846 | blacklist ${HOME}/.purple |
diff --git a/etc/profile-a-l/alpine.profile b/etc/profile-a-l/alpine.profile new file mode 100644 index 000000000..0b5cf0df0 --- /dev/null +++ b/etc/profile-a-l/alpine.profile | |||
@@ -0,0 +1,104 @@ | |||
1 | # Firejail profile for alpine | ||
2 | # Description: Text-based email and newsgroups reader | ||
3 | # This file is overwritten after every install/update | ||
4 | quiet | ||
5 | # Persistent local customizations | ||
6 | include alpine.local | ||
7 | # Persistent global definitions | ||
8 | include globals.local | ||
9 | |||
10 | # Workaround for bug https://github.com/netblue30/firejail/issues/2747 | ||
11 | # firejail --private-bin=sh --include='${CFG}/allow-bin-sh.inc' --profile=alpine sh -c '(alpine)' | ||
12 | |||
13 | noblacklist /var/mail | ||
14 | noblacklist /var/spool/mail | ||
15 | noblacklist ${DOCUMENTS} | ||
16 | noblacklist ${HOME}/.addressbook | ||
17 | noblacklist ${HOME}/.alpine-smime | ||
18 | noblacklist ${HOME}/.mailcap | ||
19 | noblacklist ${HOME}/.mh_profile | ||
20 | noblacklist ${HOME}/.mime.types | ||
21 | noblacklist ${HOME}/.newsrc | ||
22 | noblacklist ${HOME}/.pine-crash | ||
23 | noblacklist ${HOME}/.pine-debug1 | ||
24 | noblacklist ${HOME}/.pine-debug2 | ||
25 | noblacklist ${HOME}/.pine-debug3 | ||
26 | noblacklist ${HOME}/.pine-debug4 | ||
27 | noblacklist ${HOME}/.pine-interrupted-mail | ||
28 | noblacklist ${HOME}/.pinerc | ||
29 | noblacklist ${HOME}/.pinercex | ||
30 | noblacklist ${HOME}/.signature | ||
31 | noblacklist ${HOME}/mail | ||
32 | |||
33 | blacklist /tmp/.X11-unix | ||
34 | blacklist ${RUNUSER}/wayland-* | ||
35 | |||
36 | include disable-common.inc | ||
37 | include disable-devel.inc | ||
38 | include disable-exec.inc | ||
39 | include disable-interpreters.inc | ||
40 | include disable-passwdmgr.inc | ||
41 | include disable-programs.inc | ||
42 | include disable-shell.inc | ||
43 | include disable-xdg.inc | ||
44 | |||
45 | #whitelist ${DOCUMENTS} | ||
46 | #whitelist ${DOWNLOADS} | ||
47 | #whitelist ${HOME}/.addressbook | ||
48 | #whitelist ${HOME}/.alpine-smime | ||
49 | #whitelist ${HOME}/.mailcap | ||
50 | #whitelist ${HOME}/.mh_profile | ||
51 | #whitelist ${HOME}/.mime.types | ||
52 | #whitelist ${HOME}/.newsrc | ||
53 | #whitelist ${HOME}/.pine-crash | ||
54 | #whitelist ${HOME}/.pine-interrupted-mail | ||
55 | #whitelist ${HOME}/.pinerc | ||
56 | #whitelist ${HOME}/.pinercex | ||
57 | #whitelist ${HOME}/.pine-debug1 | ||
58 | #whitelist ${HOME}/.pine-debug2 | ||
59 | #whitelist ${HOME}/.pine-debug3 | ||
60 | #whitelist ${HOME}/.pine-debug4 | ||
61 | #whitelist ${HOME}/.signature | ||
62 | #whitelist ${HOME}/mail | ||
63 | whitelist /var/mail | ||
64 | whitelist /var/spool/mail | ||
65 | #include whitelist-common.inc | ||
66 | include whitelist-runuser-common.inc | ||
67 | include whitelist-usr-share-common.inc | ||
68 | include whitelist-var-common.inc | ||
69 | |||
70 | apparmor | ||
71 | caps.drop all | ||
72 | ipc-namespace | ||
73 | machine-id | ||
74 | netfilter | ||
75 | no3d | ||
76 | nodvd | ||
77 | nogroups | ||
78 | noinput | ||
79 | nonewprivs | ||
80 | noroot | ||
81 | nosound | ||
82 | notv | ||
83 | nou2f | ||
84 | novideo | ||
85 | protocol unix,inet,inet6 | ||
86 | seccomp | ||
87 | seccomp.block-secondary | ||
88 | shell none | ||
89 | tracelog | ||
90 | |||
91 | disable-mnt | ||
92 | private-bin alpine | ||
93 | private-cache | ||
94 | private-dev | ||
95 | private-etc alternatives,c-client.cf,ca-certificates,crypto-policies,host.conf,hostname,hosts,krb5.keytab,ld.so.cache,ld.so.conf,ld.so.conf.d,ld.so.preload,locale,locale.alias,locale.conf,localtime,mailcap,mime.types,nsswitch.conf,passwd,pine.conf,pinerc.fixed,pki,protocols,resolv.conf,rpc,services,ssl,terminfo,xdg | ||
96 | private-tmp | ||
97 | writable-run-user | ||
98 | writable-var | ||
99 | |||
100 | dbus-user none | ||
101 | dbus-system none | ||
102 | |||
103 | memory-deny-write-execute | ||
104 | read-only ${HOME}/.signature | ||
diff --git a/etc/profile-a-l/alpinef.profile b/etc/profile-a-l/alpinef.profile new file mode 100644 index 000000000..97b97fe5f --- /dev/null +++ b/etc/profile-a-l/alpinef.profile | |||
@@ -0,0 +1,14 @@ | |||
1 | # Firejail profile for alpinef | ||
2 | # Description: Text-based email and newsgroups reader using function keys | ||
3 | # This file is overwritten after every install/update | ||
4 | quiet | ||
5 | # Persistent local customizations | ||
6 | include alpinef.local | ||
7 | # Persistent global definitions | ||
8 | # added by included profile | ||
9 | #include globals.local | ||
10 | |||
11 | private-bin alpinef | ||
12 | |||
13 | # Redirect | ||
14 | include alpine.profile | ||
diff --git a/etc/profile-a-l/cargo.profile b/etc/profile-a-l/cargo.profile index 043fd6718..7cf04c550 100644 --- a/etc/profile-a-l/cargo.profile +++ b/etc/profile-a-l/cargo.profile | |||
@@ -34,6 +34,7 @@ include disable-xdg.inc | |||
34 | #whitelist ${HOME}/.cargo | 34 | #whitelist ${HOME}/.cargo |
35 | #whitelist ${HOME}/.rustup | 35 | #whitelist ${HOME}/.rustup |
36 | #include whitelist-common.inc | 36 | #include whitelist-common.inc |
37 | whitelist /usr/share/pkgconfig | ||
37 | include whitelist-runuser-common.inc | 38 | include whitelist-runuser-common.inc |
38 | include whitelist-usr-share-common.inc | 39 | include whitelist-usr-share-common.inc |
39 | include whitelist-var-common.inc | 40 | include whitelist-var-common.inc |
diff --git a/etc/profile-a-l/chromium-common.profile b/etc/profile-a-l/chromium-common.profile index f7493aa82..b0e0254d4 100644 --- a/etc/profile-a-l/chromium-common.profile +++ b/etc/profile-a-l/chromium-common.profile | |||
@@ -37,8 +37,9 @@ include whitelist-var-common.inc | |||
37 | # Add the next line to your chromium-common.local if your kernel allows unprivileged userns clone. | 37 | # Add the next line to your chromium-common.local if your kernel allows unprivileged userns clone. |
38 | #include chromium-common-hardened.inc.profile | 38 | #include chromium-common-hardened.inc.profile |
39 | 39 | ||
40 | # Add the next line to your chromium-common.local to allow screen sharing under wayland. | 40 | # Add the next two lines to your chromium-common.local to allow screen sharing under wayland. |
41 | #whitelist ${RUNUSER}/pipewire-0 | 41 | #whitelist ${RUNUSER}/pipewire-0 |
42 | #whitelist /usr/share/pipewire/client.conf | ||
42 | 43 | ||
43 | apparmor | 44 | apparmor |
44 | caps.keep sys_admin,sys_chroot | 45 | caps.keep sys_admin,sys_chroot |
diff --git a/etc/profile-a-l/firefox.profile b/etc/profile-a-l/firefox.profile index 7874c882f..3ad67734d 100644 --- a/etc/profile-a-l/firefox.profile +++ b/etc/profile-a-l/firefox.profile | |||
@@ -56,8 +56,9 @@ dbus-user.own org.mpris.MediaPlayer2.firefox.* | |||
56 | #dbus-user.own org.mpris.MediaPlayer2.plasma-browser-integration | 56 | #dbus-user.own org.mpris.MediaPlayer2.plasma-browser-integration |
57 | #dbus-user.talk org.kde.JobViewServer | 57 | #dbus-user.talk org.kde.JobViewServer |
58 | #dbus-user.talk org.kde.kuiserver | 58 | #dbus-user.talk org.kde.kuiserver |
59 | # Add the next two lines to your firefox.local to allow screen sharing under wayland. | 59 | # Add the next three lines to your firefox.local to allow screen sharing under wayland. |
60 | #whitelist ${RUNUSER}/pipewire-0 | 60 | #whitelist ${RUNUSER}/pipewire-0 |
61 | #whitelist /usr/share/pipewire/client.conf | ||
61 | #dbus-user.talk org.freedesktop.portal.* | 62 | #dbus-user.talk org.freedesktop.portal.* |
62 | # Add the next line to your firefox.local if screen sharing sharing still does not work | 63 | # Add the next line to your firefox.local if screen sharing sharing still does not work |
63 | # with the above lines (might depend on the portal implementation). | 64 | # with the above lines (might depend on the portal implementation). |
diff --git a/etc/profile-a-l/librewolf.profile b/etc/profile-a-l/librewolf.profile index 8e3e58f19..da047357a 100644 --- a/etc/profile-a-l/librewolf.profile +++ b/etc/profile-a-l/librewolf.profile | |||
@@ -44,8 +44,9 @@ dbus-user filter | |||
44 | #dbus-user.own org.mpris.MediaPlayer2.plasma-browser-integration | 44 | #dbus-user.own org.mpris.MediaPlayer2.plasma-browser-integration |
45 | #dbus-user.talk org.kde.JobViewServer | 45 | #dbus-user.talk org.kde.JobViewServer |
46 | #dbus-user.talk org.kde.kuiserver | 46 | #dbus-user.talk org.kde.kuiserver |
47 | # Add the next lines to your librewolf.local to allow screensharing under Wayland. | 47 | # Add the next three lines to your librewolf.local to allow screensharing under Wayland. |
48 | #whitelist ${RUNUSER}/pipewire-0 | 48 | #whitelist ${RUNUSER}/pipewire-0 |
49 | #whitelist /usr/share/pipewire/client.conf | ||
49 | #dbus-user.talk org.freedesktop.portal.* | 50 | #dbus-user.talk org.freedesktop.portal.* |
50 | # Also add the next line to your librewolf.local if screensharing does not work with | 51 | # Also add the next line to your librewolf.local if screensharing does not work with |
51 | # the above lines (depends on the portal implementation). | 52 | # the above lines (depends on the portal implementation). |
diff --git a/etc/profile-m-z/minecraft-launcher.profile b/etc/profile-m-z/minecraft-launcher.profile index 2536d0b38..1028e374a 100644 --- a/etc/profile-m-z/minecraft-launcher.profile +++ b/etc/profile-m-z/minecraft-launcher.profile | |||
@@ -31,7 +31,6 @@ include whitelist-runuser-common.inc | |||
31 | include whitelist-usr-share-common.inc | 31 | include whitelist-usr-share-common.inc |
32 | include whitelist-var-common.inc | 32 | include whitelist-var-common.inc |
33 | 33 | ||
34 | apparmor | ||
35 | caps.drop all | 34 | caps.drop all |
36 | netfilter | 35 | netfilter |
37 | nodvd | 36 | nodvd |
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config index f23488e20..e58fe39ec 100644 --- a/src/firecfg/firecfg.config +++ b/src/firecfg/firecfg.config | |||
@@ -38,6 +38,8 @@ abrowser | |||
38 | akonadi_control | 38 | akonadi_control |
39 | akregator | 39 | akregator |
40 | alacarte | 40 | alacarte |
41 | alpine | ||
42 | alpinef | ||
41 | amarok | 43 | amarok |
42 | amule | 44 | amule |
43 | amuled | 45 | amuled |
diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c index e019de36f..056640eec 100644 --- a/src/firejail/appimage.c +++ b/src/firejail/appimage.c | |||
@@ -61,9 +61,13 @@ int appimage_find_profile(const char *archive) { | |||
61 | char *ptr = strchr(buf, '\n'); | 61 | char *ptr = strchr(buf, '\n'); |
62 | if (ptr) | 62 | if (ptr) |
63 | *ptr = '\0'; | 63 | *ptr = '\0'; |
64 | if (strcasestr(archive, buf)) | 64 | if (strcasestr(archive, buf)) { |
65 | fclose(fp); | ||
65 | return profile_find_firejail(buf, 1); | 66 | return profile_find_firejail(buf, 1); |
67 | } | ||
66 | } | 68 | } |
69 | |||
70 | fclose(fp); | ||
67 | return 0; | 71 | return 0; |
68 | 72 | ||
69 | } | 73 | } |
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c index f3ab0a6d8..1e9f4b641 100644 --- a/src/firejail/checkcfg.c +++ b/src/firejail/checkcfg.c | |||
@@ -35,6 +35,7 @@ char *xvfb_extra_params = ""; | |||
35 | char *netfilter_default = NULL; | 35 | char *netfilter_default = NULL; |
36 | unsigned long join_timeout = 5000000; // microseconds | 36 | unsigned long join_timeout = 5000000; // microseconds |
37 | char *config_seccomp_error_action_str = "EPERM"; | 37 | char *config_seccomp_error_action_str = "EPERM"; |
38 | char *config_seccomp_filter_add = NULL; | ||
38 | char **whitelist_reject_topdirs = NULL; | 39 | char **whitelist_reject_topdirs = NULL; |
39 | 40 | ||
40 | int checkcfg(int val) { | 41 | int checkcfg(int val) { |
@@ -225,6 +226,10 @@ int checkcfg(int val) { | |||
225 | else if (strncmp(ptr, "join-timeout ", 13) == 0) | 226 | else if (strncmp(ptr, "join-timeout ", 13) == 0) |
226 | join_timeout = strtoul(ptr + 13, NULL, 10) * 1000000; // seconds to microseconds | 227 | join_timeout = strtoul(ptr + 13, NULL, 10) * 1000000; // seconds to microseconds |
227 | 228 | ||
229 | // add rules to default seccomp filter | ||
230 | else if (strncmp(ptr, "seccomp-filter-add ", 19) == 0) | ||
231 | config_seccomp_filter_add = seccomp_check_list(ptr + 19); | ||
232 | |||
228 | // seccomp error action | 233 | // seccomp error action |
229 | else if (strncmp(ptr, "seccomp-error-action ", 21) == 0) { | 234 | else if (strncmp(ptr, "seccomp-error-action ", 21) == 0) { |
230 | if (strcmp(ptr + 21, "kill") == 0) | 235 | if (strcmp(ptr + 21, "kill") == 0) |
diff --git a/src/firejail/dbus.c b/src/firejail/dbus.c index bfa28fcba..9a4cb2e6b 100644 --- a/src/firejail/dbus.c +++ b/src/firejail/dbus.c | |||
@@ -470,7 +470,7 @@ void dbus_apply_policy(void) { | |||
470 | create_empty_dir_as_root(RUN_DBUS_DIR, 0755); | 470 | create_empty_dir_as_root(RUN_DBUS_DIR, 0755); |
471 | 471 | ||
472 | if (arg_dbus_user != DBUS_POLICY_ALLOW) { | 472 | if (arg_dbus_user != DBUS_POLICY_ALLOW) { |
473 | create_empty_file_as_root(RUN_DBUS_USER_SOCKET, 0700); | 473 | create_empty_file_as_root(RUN_DBUS_USER_SOCKET, 0600); |
474 | 474 | ||
475 | if (arg_dbus_user == DBUS_POLICY_FILTER) { | 475 | if (arg_dbus_user == DBUS_POLICY_FILTER) { |
476 | assert(dbus_user_proxy_socket != NULL); | 476 | assert(dbus_user_proxy_socket != NULL); |
@@ -509,7 +509,7 @@ void dbus_apply_policy(void) { | |||
509 | } | 509 | } |
510 | 510 | ||
511 | if (arg_dbus_system != DBUS_POLICY_ALLOW) { | 511 | if (arg_dbus_system != DBUS_POLICY_ALLOW) { |
512 | create_empty_file_as_root(RUN_DBUS_SYSTEM_SOCKET, 0700); | 512 | create_empty_file_as_root(RUN_DBUS_SYSTEM_SOCKET, 0600); |
513 | 513 | ||
514 | if (arg_dbus_system == DBUS_POLICY_FILTER) { | 514 | if (arg_dbus_system == DBUS_POLICY_FILTER) { |
515 | assert(dbus_system_proxy_socket != NULL); | 515 | assert(dbus_system_proxy_socket != NULL); |
diff --git a/src/firejail/dhcp.c b/src/firejail/dhcp.c index 47dd39ac0..ec482e2ea 100644 --- a/src/firejail/dhcp.c +++ b/src/firejail/dhcp.c | |||
@@ -160,9 +160,6 @@ void dhcp_start(void) { | |||
160 | exit(1); | 160 | exit(1); |
161 | } | 161 | } |
162 | 162 | ||
163 | sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", dhclient_path, RUN_MNT_DIR); | ||
164 | dhclient_path = RUN_MNT_DIR "/dhclient"; | ||
165 | |||
166 | EUID_ROOT(); | 163 | EUID_ROOT(); |
167 | if (mkdir(RUN_DHCLIENT_DIR, 0700)) | 164 | if (mkdir(RUN_DHCLIENT_DIR, 0700)) |
168 | errExit("mkdir"); | 165 | errExit("mkdir"); |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 622be4d97..9971d30b6 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; eithe r version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
@@ -498,6 +498,7 @@ int macro_id(const char *name); | |||
498 | void errLogExit(char* fmt, ...) __attribute__((noreturn)); | 498 | void errLogExit(char* fmt, ...) __attribute__((noreturn)); |
499 | void fwarning(char* fmt, ...); | 499 | void fwarning(char* fmt, ...); |
500 | void fmessage(char* fmt, ...); | 500 | void fmessage(char* fmt, ...); |
501 | long long unsigned parse_arg_size(char *str); | ||
501 | void drop_privs(int nogroups); | 502 | void drop_privs(int nogroups); |
502 | int mkpath_as_root(const char* path); | 503 | int mkpath_as_root(const char* path); |
503 | void extract_command_name(int index, char **argv); | 504 | void extract_command_name(int index, char **argv); |
@@ -507,7 +508,7 @@ void logargs(int argc, char **argv) ; | |||
507 | void logerr(const char *msg); | 508 | void logerr(const char *msg); |
508 | void set_nice(int inc); | 509 | void set_nice(int inc); |
509 | int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode); | 510 | int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode); |
510 | void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode); | 511 | void copy_file_as_user(const char *srcname, const char *destname, mode_t mode); |
511 | void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode); | 512 | void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode); |
512 | void touch_file_as_user(const char *fname, mode_t mode); | 513 | void touch_file_as_user(const char *fname, mode_t mode); |
513 | int is_dir(const char *fname); | 514 | int is_dir(const char *fname); |
@@ -809,6 +810,7 @@ extern char *xvfb_extra_params; | |||
809 | extern char *netfilter_default; | 810 | extern char *netfilter_default; |
810 | extern unsigned long join_timeout; | 811 | extern unsigned long join_timeout; |
811 | extern char *config_seccomp_error_action_str; | 812 | extern char *config_seccomp_error_action_str; |
813 | extern char *config_seccomp_filter_add; | ||
812 | extern char **whitelist_reject_topdirs; | 814 | extern char **whitelist_reject_topdirs; |
813 | 815 | ||
814 | int checkcfg(int val); | 816 | int checkcfg(int val); |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 803b081c9..806fa9249 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -171,21 +171,28 @@ static void disable_file(OPERATION op, const char *filename) { | |||
171 | fs_remount_rec(fname, op); | 171 | fs_remount_rec(fname, op); |
172 | } | 172 | } |
173 | else if (op == MOUNT_TMPFS) { | 173 | else if (op == MOUNT_TMPFS) { |
174 | if (S_ISDIR(s.st_mode)) { | 174 | if (!S_ISDIR(s.st_mode)) { |
175 | if (getuid()) { | 175 | fwarning("%s is not a directory; cannot mount a tmpfs on top of it.\n", fname); |
176 | if (strncmp(cfg.homedir, fname, strlen(cfg.homedir)) != 0 || | 176 | free(fname); |
177 | fname[strlen(cfg.homedir)] != '/') { | 177 | return; |
178 | fprintf(stderr, "Error: tmpfs outside $HOME is only available for root\n"); | 178 | } |
179 | exit(1); | 179 | |
180 | } | 180 | uid_t uid = getuid(); |
181 | if (uid != 0) { | ||
182 | // only user owned directories in user home | ||
183 | if (s.st_uid != uid || | ||
184 | strncmp(cfg.homedir, fname, strlen(cfg.homedir)) != 0 || | ||
185 | fname[strlen(cfg.homedir)] != '/') { | ||
186 | fwarning("you are not allowed to mount a tmpfs on %s\n", fname); | ||
187 | free(fname); | ||
188 | return; | ||
181 | } | 189 | } |
182 | // fs_tmpfs returns with EUID 0 | ||
183 | fs_tmpfs(fname, getuid()); | ||
184 | selinux_relabel_path(fname, fname); | ||
185 | EUID_USER(); | ||
186 | } | 190 | } |
187 | else | 191 | |
188 | fwarning("%s is not a directory; cannot mount a tmpfs on top of it.\n", fname); | 192 | fs_tmpfs(fname, uid); |
193 | EUID_USER(); // fs_tmpfs returns with EUID 0 | ||
194 | |||
195 | selinux_relabel_path(fname, fname); | ||
189 | } | 196 | } |
190 | else | 197 | else |
191 | assert(0); | 198 | assert(0); |
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index eab952eb8..0ed476063 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c | |||
@@ -34,12 +34,13 @@ | |||
34 | #define O_PATH 010000000 | 34 | #define O_PATH 010000000 |
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | static void skel(const char *homedir, uid_t u, gid_t g) { | 37 | static void skel(const char *homedir) { |
38 | char *fname; | 38 | EUID_ASSERT(); |
39 | 39 | ||
40 | // zsh | 40 | // zsh |
41 | if (!arg_shell_none && (strcmp(cfg.shell,"/usr/bin/zsh") == 0 || strcmp(cfg.shell,"/bin/zsh") == 0)) { | 41 | if (!arg_shell_none && (strcmp(cfg.shell,"/usr/bin/zsh") == 0 || strcmp(cfg.shell,"/bin/zsh") == 0)) { |
42 | // copy skel files | 42 | // copy skel files |
43 | char *fname; | ||
43 | if (asprintf(&fname, "%s/.zshrc", homedir) == -1) | 44 | if (asprintf(&fname, "%s/.zshrc", homedir) == -1) |
44 | errExit("asprintf"); | 45 | errExit("asprintf"); |
45 | // don't copy it if we already have the file | 46 | // don't copy it if we already have the file |
@@ -50,7 +51,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
50 | exit(1); | 51 | exit(1); |
51 | } | 52 | } |
52 | if (access("/etc/skel/.zshrc", R_OK) == 0) { | 53 | if (access("/etc/skel/.zshrc", R_OK) == 0) { |
53 | copy_file_as_user("/etc/skel/.zshrc", fname, u, g, 0644); // regular user | 54 | copy_file_as_user("/etc/skel/.zshrc", fname, 0644); // regular user |
54 | fs_logger("clone /etc/skel/.zshrc"); | 55 | fs_logger("clone /etc/skel/.zshrc"); |
55 | fs_logger2("clone", fname); | 56 | fs_logger2("clone", fname); |
56 | } | 57 | } |
@@ -64,6 +65,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
64 | // csh | 65 | // csh |
65 | else if (!arg_shell_none && strcmp(cfg.shell,"/bin/csh") == 0) { | 66 | else if (!arg_shell_none && strcmp(cfg.shell,"/bin/csh") == 0) { |
66 | // copy skel files | 67 | // copy skel files |
68 | char *fname; | ||
67 | if (asprintf(&fname, "%s/.cshrc", homedir) == -1) | 69 | if (asprintf(&fname, "%s/.cshrc", homedir) == -1) |
68 | errExit("asprintf"); | 70 | errExit("asprintf"); |
69 | // don't copy it if we already have the file | 71 | // don't copy it if we already have the file |
@@ -74,7 +76,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
74 | exit(1); | 76 | exit(1); |
75 | } | 77 | } |
76 | if (access("/etc/skel/.cshrc", R_OK) == 0) { | 78 | if (access("/etc/skel/.cshrc", R_OK) == 0) { |
77 | copy_file_as_user("/etc/skel/.cshrc", fname, u, g, 0644); // regular user | 79 | copy_file_as_user("/etc/skel/.cshrc", fname, 0644); // regular user |
78 | fs_logger("clone /etc/skel/.cshrc"); | 80 | fs_logger("clone /etc/skel/.cshrc"); |
79 | fs_logger2("clone", fname); | 81 | fs_logger2("clone", fname); |
80 | } | 82 | } |
@@ -88,6 +90,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
88 | // bash etc. | 90 | // bash etc. |
89 | else { | 91 | else { |
90 | // copy skel files | 92 | // copy skel files |
93 | char *fname; | ||
91 | if (asprintf(&fname, "%s/.bashrc", homedir) == -1) | 94 | if (asprintf(&fname, "%s/.bashrc", homedir) == -1) |
92 | errExit("asprintf"); | 95 | errExit("asprintf"); |
93 | // don't copy it if we already have the file | 96 | // don't copy it if we already have the file |
@@ -98,7 +101,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
98 | exit(1); | 101 | exit(1); |
99 | } | 102 | } |
100 | if (access("/etc/skel/.bashrc", R_OK) == 0) { | 103 | if (access("/etc/skel/.bashrc", R_OK) == 0) { |
101 | copy_file_as_user("/etc/skel/.bashrc", fname, u, g, 0644); // regular user | 104 | copy_file_as_user("/etc/skel/.bashrc", fname, 0644); // regular user |
102 | fs_logger("clone /etc/skel/.bashrc"); | 105 | fs_logger("clone /etc/skel/.bashrc"); |
103 | fs_logger2("clone", fname); | 106 | fs_logger2("clone", fname); |
104 | } | 107 | } |
@@ -108,6 +111,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
108 | } | 111 | } |
109 | 112 | ||
110 | static int store_xauthority(void) { | 113 | static int store_xauthority(void) { |
114 | EUID_ASSERT(); | ||
111 | if (arg_x11_block) | 115 | if (arg_x11_block) |
112 | return 0; | 116 | return 0; |
113 | 117 | ||
@@ -118,7 +122,7 @@ static int store_xauthority(void) { | |||
118 | errExit("asprintf"); | 122 | errExit("asprintf"); |
119 | 123 | ||
120 | struct stat s; | 124 | struct stat s; |
121 | if (lstat_as_user(src, &s) == 0) { | 125 | if (lstat(src, &s) == 0) { |
122 | if (S_ISLNK(s.st_mode)) { | 126 | if (S_ISLNK(s.st_mode)) { |
123 | fwarning("invalid .Xauthority file\n"); | 127 | fwarning("invalid .Xauthority file\n"); |
124 | free(src); | 128 | free(src); |
@@ -126,6 +130,7 @@ static int store_xauthority(void) { | |||
126 | } | 130 | } |
127 | 131 | ||
128 | // create an empty file as root, and change ownership to user | 132 | // create an empty file as root, and change ownership to user |
133 | EUID_ROOT(); | ||
129 | FILE *fp = fopen(dest, "we"); | 134 | FILE *fp = fopen(dest, "we"); |
130 | if (fp) { | 135 | if (fp) { |
131 | fprintf(fp, "\n"); | 136 | fprintf(fp, "\n"); |
@@ -134,10 +139,11 @@ static int store_xauthority(void) { | |||
134 | } | 139 | } |
135 | else | 140 | else |
136 | errExit("fopen"); | 141 | errExit("fopen"); |
142 | EUID_USER(); | ||
137 | 143 | ||
138 | copy_file_as_user(src, dest, getuid(), getgid(), 0600); // regular user | 144 | copy_file_as_user(src, dest, 0600); // regular user |
139 | fs_logger2("clone", dest); | ||
140 | selinux_relabel_path(dest, src); | 145 | selinux_relabel_path(dest, src); |
146 | fs_logger2("clone", dest); | ||
141 | free(src); | 147 | free(src); |
142 | return 1; // file copied | 148 | return 1; // file copied |
143 | } | 149 | } |
@@ -147,6 +153,7 @@ static int store_xauthority(void) { | |||
147 | } | 153 | } |
148 | 154 | ||
149 | static int store_asoundrc(void) { | 155 | static int store_asoundrc(void) { |
156 | EUID_ASSERT(); | ||
150 | if (arg_nosound) | 157 | if (arg_nosound) |
151 | return 0; | 158 | return 0; |
152 | 159 | ||
@@ -157,11 +164,11 @@ static int store_asoundrc(void) { | |||
157 | errExit("asprintf"); | 164 | errExit("asprintf"); |
158 | 165 | ||
159 | struct stat s; | 166 | struct stat s; |
160 | if (lstat_as_user(src, &s) == 0) { | 167 | if (lstat(src, &s) == 0) { |
161 | if (S_ISLNK(s.st_mode)) { | 168 | if (S_ISLNK(s.st_mode)) { |
162 | // make sure the real path of the file is inside the home directory | 169 | // make sure the real path of the file is inside the home directory |
163 | /* coverity[toctou] */ | 170 | /* coverity[toctou] */ |
164 | char *rp = realpath_as_user(src); | 171 | char *rp = realpath(src, NULL); |
165 | if (!rp) { | 172 | if (!rp) { |
166 | fprintf(stderr, "Error: Cannot access %s\n", src); | 173 | fprintf(stderr, "Error: Cannot access %s\n", src); |
167 | exit(1); | 174 | exit(1); |
@@ -174,6 +181,7 @@ static int store_asoundrc(void) { | |||
174 | } | 181 | } |
175 | 182 | ||
176 | // create an empty file as root, and change ownership to user | 183 | // create an empty file as root, and change ownership to user |
184 | EUID_ROOT(); | ||
177 | FILE *fp = fopen(dest, "we"); | 185 | FILE *fp = fopen(dest, "we"); |
178 | if (fp) { | 186 | if (fp) { |
179 | fprintf(fp, "\n"); | 187 | fprintf(fp, "\n"); |
@@ -182,10 +190,11 @@ static int store_asoundrc(void) { | |||
182 | } | 190 | } |
183 | else | 191 | else |
184 | errExit("fopen"); | 192 | errExit("fopen"); |
193 | EUID_USER(); | ||
185 | 194 | ||
186 | copy_file_as_user(src, dest, getuid(), getgid(), 0644); // regular user | 195 | copy_file_as_user(src, dest, 0644); // regular user |
187 | selinux_relabel_path(dest, src); | ||
188 | fs_logger2("clone", dest); | 196 | fs_logger2("clone", dest); |
197 | selinux_relabel_path(dest, src); | ||
189 | free(src); | 198 | free(src); |
190 | return 1; // file copied | 199 | return 1; // file copied |
191 | } | 200 | } |
@@ -195,6 +204,7 @@ static int store_asoundrc(void) { | |||
195 | } | 204 | } |
196 | 205 | ||
197 | static void copy_xauthority(void) { | 206 | static void copy_xauthority(void) { |
207 | EUID_ASSERT(); | ||
198 | // copy XAUTHORITY_FILE in the new home directory | 208 | // copy XAUTHORITY_FILE in the new home directory |
199 | char *src = RUN_XAUTHORITY_FILE ; | 209 | char *src = RUN_XAUTHORITY_FILE ; |
200 | char *dest; | 210 | char *dest; |
@@ -207,16 +217,18 @@ static void copy_xauthority(void) { | |||
207 | exit(1); | 217 | exit(1); |
208 | } | 218 | } |
209 | 219 | ||
210 | copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user | 220 | copy_file_as_user(src, dest, S_IRUSR | S_IWUSR); // regular user |
211 | selinux_relabel_path(dest, src); | ||
212 | fs_logger2("clone", dest); | 221 | fs_logger2("clone", dest); |
222 | selinux_relabel_path(dest, dest); | ||
213 | free(dest); | 223 | free(dest); |
214 | 224 | ||
215 | // delete the temporary file | 225 | EUID_ROOT(); |
216 | unlink(src); | 226 | unlink(src); // delete the temporary file |
227 | EUID_USER(); | ||
217 | } | 228 | } |
218 | 229 | ||
219 | static void copy_asoundrc(void) { | 230 | static void copy_asoundrc(void) { |
231 | EUID_ASSERT(); | ||
220 | // copy ASOUNDRC_FILE in the new home directory | 232 | // copy ASOUNDRC_FILE in the new home directory |
221 | char *src = RUN_ASOUNDRC_FILE ; | 233 | char *src = RUN_ASOUNDRC_FILE ; |
222 | char *dest; | 234 | char *dest; |
@@ -229,13 +241,14 @@ static void copy_asoundrc(void) { | |||
229 | exit(1); | 241 | exit(1); |
230 | } | 242 | } |
231 | 243 | ||
232 | copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user | 244 | copy_file_as_user(src, dest, S_IRUSR | S_IWUSR); // regular user |
233 | selinux_relabel_path(dest, src); | ||
234 | fs_logger2("clone", dest); | 245 | fs_logger2("clone", dest); |
246 | selinux_relabel_path(dest, dest); | ||
235 | free(dest); | 247 | free(dest); |
236 | 248 | ||
237 | // delete the temporary file | 249 | EUID_ROOT(); |
238 | unlink(src); | 250 | unlink(src); // delete the temporary file |
251 | EUID_USER(); | ||
239 | } | 252 | } |
240 | 253 | ||
241 | // private mode (--private=homedir): | 254 | // private mode (--private=homedir): |
@@ -248,18 +261,18 @@ void fs_private_homedir(void) { | |||
248 | char *private_homedir = cfg.home_private; | 261 | char *private_homedir = cfg.home_private; |
249 | assert(homedir); | 262 | assert(homedir); |
250 | assert(private_homedir); | 263 | assert(private_homedir); |
264 | EUID_ASSERT(); | ||
265 | |||
266 | uid_t u = getuid(); | ||
267 | // gid_t g = getgid(); | ||
251 | 268 | ||
252 | int xflag = store_xauthority(); | 269 | int xflag = store_xauthority(); |
253 | int aflag = store_asoundrc(); | 270 | int aflag = store_asoundrc(); |
254 | 271 | ||
255 | uid_t u = getuid(); | ||
256 | gid_t g = getgid(); | ||
257 | |||
258 | // mount bind private_homedir on top of homedir | 272 | // mount bind private_homedir on top of homedir |
259 | if (arg_debug) | 273 | if (arg_debug) |
260 | printf("Mount-bind %s on top of %s\n", private_homedir, homedir); | 274 | printf("Mount-bind %s on top of %s\n", private_homedir, homedir); |
261 | // get file descriptors for homedir and private_homedir, fails if there is any symlink | 275 | // get file descriptors for homedir and private_homedir, fails if there is any symlink |
262 | EUID_USER(); | ||
263 | int src = safer_openat(-1, private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 276 | int src = safer_openat(-1, private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
264 | if (src == -1) | 277 | if (src == -1) |
265 | errExit("opening private directory"); | 278 | errExit("opening private directory"); |
@@ -287,6 +300,7 @@ void fs_private_homedir(void) { | |||
287 | EUID_ROOT(); | 300 | EUID_ROOT(); |
288 | if (bind_mount_by_fd(src, dst)) | 301 | if (bind_mount_by_fd(src, dst)) |
289 | errExit("mount bind"); | 302 | errExit("mount bind"); |
303 | EUID_USER(); | ||
290 | 304 | ||
291 | // check /proc/self/mountinfo to confirm the mount is ok | 305 | // check /proc/self/mountinfo to confirm the mount is ok |
292 | MountData *mptr = get_last_mount(); | 306 | MountData *mptr = get_last_mount(); |
@@ -305,6 +319,7 @@ void fs_private_homedir(void) { | |||
305 | // if (chmod(homedir, s.st_mode) == -1) | 319 | // if (chmod(homedir, s.st_mode) == -1) |
306 | // errExit("mount-bind chmod"); | 320 | // errExit("mount-bind chmod"); |
307 | 321 | ||
322 | EUID_ROOT(); | ||
308 | if (u != 0) { | 323 | if (u != 0) { |
309 | // mask /root | 324 | // mask /root |
310 | if (arg_debug) | 325 | if (arg_debug) |
@@ -323,8 +338,9 @@ void fs_private_homedir(void) { | |||
323 | selinux_relabel_path("/home", "/home"); | 338 | selinux_relabel_path("/home", "/home"); |
324 | fs_logger("tmpfs /home"); | 339 | fs_logger("tmpfs /home"); |
325 | } | 340 | } |
341 | EUID_USER(); | ||
326 | 342 | ||
327 | skel(homedir, u, g); | 343 | skel(homedir); |
328 | if (xflag) | 344 | if (xflag) |
329 | copy_xauthority(); | 345 | copy_xauthority(); |
330 | if (aflag) | 346 | if (aflag) |
@@ -339,12 +355,15 @@ void fs_private_homedir(void) { | |||
339 | void fs_private(void) { | 355 | void fs_private(void) { |
340 | char *homedir = cfg.homedir; | 356 | char *homedir = cfg.homedir; |
341 | assert(homedir); | 357 | assert(homedir); |
358 | EUID_ASSERT(); | ||
359 | |||
342 | uid_t u = getuid(); | 360 | uid_t u = getuid(); |
343 | gid_t g = getgid(); | 361 | gid_t g = getgid(); |
344 | 362 | ||
345 | int xflag = store_xauthority(); | 363 | int xflag = store_xauthority(); |
346 | int aflag = store_asoundrc(); | 364 | int aflag = store_asoundrc(); |
347 | 365 | ||
366 | EUID_ROOT(); | ||
348 | // mask /root | 367 | // mask /root |
349 | if (arg_debug) | 368 | if (arg_debug) |
350 | printf("Mounting a new /root directory\n"); | 369 | printf("Mounting a new /root directory\n"); |
@@ -387,8 +406,9 @@ void fs_private(void) { | |||
387 | 406 | ||
388 | selinux_relabel_path(homedir, homedir); | 407 | selinux_relabel_path(homedir, homedir); |
389 | } | 408 | } |
409 | EUID_USER(); | ||
390 | 410 | ||
391 | skel(homedir, u, g); | 411 | skel(homedir); |
392 | if (xflag) | 412 | if (xflag) |
393 | copy_xauthority(); | 413 | copy_xauthority(); |
394 | if (aflag) | 414 | if (aflag) |
@@ -530,26 +550,29 @@ static void duplicate(char *name) { | |||
530 | // set skel files, | 550 | // set skel files, |
531 | // restore .Xauthority | 551 | // restore .Xauthority |
532 | void fs_private_home_list(void) { | 552 | void fs_private_home_list(void) { |
533 | timetrace_start(); | ||
534 | |||
535 | char *homedir = cfg.homedir; | 553 | char *homedir = cfg.homedir; |
536 | char *private_list = cfg.home_private_keep; | 554 | char *private_list = cfg.home_private_keep; |
537 | assert(homedir); | 555 | assert(homedir); |
538 | assert(private_list); | 556 | assert(private_list); |
557 | EUID_ASSERT(); | ||
539 | 558 | ||
540 | int xflag = store_xauthority(); | 559 | timetrace_start(); |
541 | int aflag = store_asoundrc(); | ||
542 | 560 | ||
543 | uid_t uid = getuid(); | 561 | uid_t uid = getuid(); |
544 | gid_t gid = getgid(); | 562 | gid_t gid = getgid(); |
545 | 563 | ||
564 | int xflag = store_xauthority(); | ||
565 | int aflag = store_asoundrc(); | ||
566 | |||
546 | // create /run/firejail/mnt/home directory | 567 | // create /run/firejail/mnt/home directory |
568 | EUID_ROOT(); | ||
547 | mkdir_attr(RUN_HOME_DIR, 0755, uid, gid); | 569 | mkdir_attr(RUN_HOME_DIR, 0755, uid, gid); |
548 | selinux_relabel_path(RUN_HOME_DIR, homedir); | 570 | selinux_relabel_path(RUN_HOME_DIR, homedir); |
571 | |||
549 | fs_logger_print(); // save the current log | 572 | fs_logger_print(); // save the current log |
573 | EUID_USER(); | ||
550 | 574 | ||
551 | // copy the list of files in the new home directory | 575 | // copy the list of files in the new home directory |
552 | EUID_USER(); | ||
553 | if (arg_debug) | 576 | if (arg_debug) |
554 | printf("Copying files in the new home:\n"); | 577 | printf("Copying files in the new home:\n"); |
555 | char *dlist = strdup(cfg.home_private_keep); | 578 | char *dlist = strdup(cfg.home_private_keep); |
@@ -587,6 +610,7 @@ void fs_private_home_list(void) { | |||
587 | EUID_ROOT(); | 610 | EUID_ROOT(); |
588 | if (bind_mount_path_to_fd(RUN_HOME_DIR, fd)) | 611 | if (bind_mount_path_to_fd(RUN_HOME_DIR, fd)) |
589 | errExit("mount bind"); | 612 | errExit("mount bind"); |
613 | EUID_USER(); | ||
590 | close(fd); | 614 | close(fd); |
591 | 615 | ||
592 | // check /proc/self/mountinfo to confirm the mount is ok | 616 | // check /proc/self/mountinfo to confirm the mount is ok |
@@ -595,11 +619,7 @@ void fs_private_home_list(void) { | |||
595 | errLogExit("invalid private-home mount"); | 619 | errLogExit("invalid private-home mount"); |
596 | fs_logger2("tmpfs", homedir); | 620 | fs_logger2("tmpfs", homedir); |
597 | 621 | ||
598 | // mask RUN_HOME_DIR, it is writable and not noexec | 622 | EUID_ROOT(); |
599 | if (mount("tmpfs", RUN_HOME_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
600 | errExit("mounting tmpfs"); | ||
601 | fs_logger2("tmpfs", RUN_HOME_DIR); | ||
602 | |||
603 | if (uid != 0) { | 623 | if (uid != 0) { |
604 | // mask /root | 624 | // mask /root |
605 | if (arg_debug) | 625 | if (arg_debug) |
@@ -619,7 +639,12 @@ void fs_private_home_list(void) { | |||
619 | fs_logger("tmpfs /home"); | 639 | fs_logger("tmpfs /home"); |
620 | } | 640 | } |
621 | 641 | ||
622 | skel(homedir, uid, gid); | 642 | // mask RUN_HOME_DIR, it is writable and not noexec |
643 | if (mount("tmpfs", RUN_HOME_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
644 | errExit("mounting tmpfs"); | ||
645 | EUID_USER(); | ||
646 | |||
647 | skel(homedir); | ||
623 | if (xflag) | 648 | if (xflag) |
624 | copy_xauthority(); | 649 | copy_xauthority(); |
625 | if (aflag) | 650 | if (aflag) |
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c index 370035a4d..943f275de 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c | |||
@@ -374,9 +374,11 @@ static void tmpfs_topdirs(const TopDir *topdirs) { | |||
374 | } | 374 | } |
375 | 375 | ||
376 | // user home directory | 376 | // user home directory |
377 | if (tmpfs_home) | 377 | if (tmpfs_home) { |
378 | // checks owner if outside /home | 378 | EUID_USER(); |
379 | fs_private(); | 379 | fs_private(); // checks owner if outside /home |
380 | EUID_ROOT(); | ||
381 | } | ||
380 | 382 | ||
381 | // /run/user/$UID directory | 383 | // /run/user/$UID directory |
382 | if (tmpfs_runuser) { | 384 | if (tmpfs_runuser) { |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 86c6575e2..7b32f6f07 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -967,7 +967,7 @@ void filter_add_blacklist_override(int fd, int syscall, int arg, void *ptrarg, b | |||
967 | static int check_postexec(const char *list) { | 967 | static int check_postexec(const char *list) { |
968 | char *prelist, *postlist; | 968 | char *prelist, *postlist; |
969 | 969 | ||
970 | if (list) { | 970 | if (list && list[0]) { |
971 | syscalls_in_list(list, "@default-keep", -1, &prelist, &postlist, true); | 971 | syscalls_in_list(list, "@default-keep", -1, &prelist, &postlist, true); |
972 | if (postlist) | 972 | if (postlist) |
973 | return 1; | 973 | return 1; |
@@ -1496,8 +1496,11 @@ int main(int argc, char **argv, char **envp) { | |||
1496 | arg_rlimit_nproc = 1; | 1496 | arg_rlimit_nproc = 1; |
1497 | } | 1497 | } |
1498 | else if (strncmp(argv[i], "--rlimit-fsize=", 15) == 0) { | 1498 | else if (strncmp(argv[i], "--rlimit-fsize=", 15) == 0) { |
1499 | check_unsigned(argv[i] + 15, "Error: invalid rlimit"); | 1499 | cfg.rlimit_fsize = parse_arg_size(argv[i] + 15); |
1500 | sscanf(argv[i] + 15, "%llu", &cfg.rlimit_fsize); | 1500 | if (cfg.rlimit_fsize == 0) { |
1501 | perror("Error: invalid rlimit-fsize. Only use positive numbers and k, m or g suffix."); | ||
1502 | exit(1); | ||
1503 | } | ||
1501 | arg_rlimit_fsize = 1; | 1504 | arg_rlimit_fsize = 1; |
1502 | } | 1505 | } |
1503 | else if (strncmp(argv[i], "--rlimit-sigpending=", 20) == 0) { | 1506 | else if (strncmp(argv[i], "--rlimit-sigpending=", 20) == 0) { |
@@ -1506,8 +1509,11 @@ int main(int argc, char **argv, char **envp) { | |||
1506 | arg_rlimit_sigpending = 1; | 1509 | arg_rlimit_sigpending = 1; |
1507 | } | 1510 | } |
1508 | else if (strncmp(argv[i], "--rlimit-as=", 12) == 0) { | 1511 | else if (strncmp(argv[i], "--rlimit-as=", 12) == 0) { |
1509 | check_unsigned(argv[i] + 12, "Error: invalid rlimit"); | 1512 | cfg.rlimit_as = parse_arg_size(argv[i] + 12); |
1510 | sscanf(argv[i] + 12, "%llu", &cfg.rlimit_as); | 1513 | if (cfg.rlimit_as == 0) { |
1514 | perror("Error: invalid rlimit-as. Only use positive numbers and k, m or g suffix."); | ||
1515 | exit(1); | ||
1516 | } | ||
1511 | arg_rlimit_as = 1; | 1517 | arg_rlimit_as = 1; |
1512 | } | 1518 | } |
1513 | else if (strncmp(argv[i], "--ipc-namespace", 15) == 0) | 1519 | else if (strncmp(argv[i], "--ipc-namespace", 15) == 0) |
@@ -2889,6 +2895,15 @@ int main(int argc, char **argv, char **envp) { | |||
2889 | // check network configuration options - it will exit if anything went wrong | 2895 | // check network configuration options - it will exit if anything went wrong |
2890 | net_check_cfg(); | 2896 | net_check_cfg(); |
2891 | 2897 | ||
2898 | // customization of default seccomp filter | ||
2899 | if (config_seccomp_filter_add) { | ||
2900 | if (arg_seccomp && !cfg.seccomp_list_keep && !cfg.seccomp_list_drop) | ||
2901 | profile_list_augment(&cfg.seccomp_list, config_seccomp_filter_add); | ||
2902 | |||
2903 | if (arg_seccomp32 && !cfg.seccomp_list_keep32 && !cfg.seccomp_list_drop32) | ||
2904 | profile_list_augment(&cfg.seccomp_list32, config_seccomp_filter_add); | ||
2905 | } | ||
2906 | |||
2892 | if (arg_seccomp) | 2907 | if (arg_seccomp) |
2893 | arg_seccomp_postexec = check_postexec(cfg.seccomp_list) || check_postexec(cfg.seccomp_list_drop); | 2908 | arg_seccomp_postexec = check_postexec(cfg.seccomp_list) || check_postexec(cfg.seccomp_list_drop); |
2894 | 2909 | ||
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 8675a1712..7b21eb387 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -1510,8 +1510,11 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1510 | arg_rlimit_nproc = 1; | 1510 | arg_rlimit_nproc = 1; |
1511 | } | 1511 | } |
1512 | else if (strncmp(ptr, "rlimit-fsize ", 13) == 0) { | 1512 | else if (strncmp(ptr, "rlimit-fsize ", 13) == 0) { |
1513 | check_unsigned(ptr + 13, "Error: invalid rlimit in profile file: "); | 1513 | cfg.rlimit_fsize = parse_arg_size(ptr + 13); |
1514 | sscanf(ptr + 13, "%llu", &cfg.rlimit_fsize); | 1514 | if (cfg.rlimit_fsize == 0) { |
1515 | perror("Error: invalid rlimit-fsize in profile file. Only use positive numbers and k, m or g suffix."); | ||
1516 | exit(1); | ||
1517 | } | ||
1515 | arg_rlimit_fsize = 1; | 1518 | arg_rlimit_fsize = 1; |
1516 | } | 1519 | } |
1517 | else if (strncmp(ptr, "rlimit-sigpending ", 18) == 0) { | 1520 | else if (strncmp(ptr, "rlimit-sigpending ", 18) == 0) { |
@@ -1520,8 +1523,11 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1520 | arg_rlimit_sigpending = 1; | 1523 | arg_rlimit_sigpending = 1; |
1521 | } | 1524 | } |
1522 | else if (strncmp(ptr, "rlimit-as ", 10) == 0) { | 1525 | else if (strncmp(ptr, "rlimit-as ", 10) == 0) { |
1523 | check_unsigned(ptr + 10, "Error: invalid rlimit in profile file: "); | 1526 | cfg.rlimit_as = parse_arg_size(ptr + 10); |
1524 | sscanf(ptr + 10, "%llu", &cfg.rlimit_as); | 1527 | if (cfg.rlimit_as == 0) { |
1528 | perror("Error: invalid rlimit-as in profile file. Only use positive numbers and k, m or g suffix."); | ||
1529 | exit(1); | ||
1530 | } | ||
1525 | arg_rlimit_as = 1; | 1531 | arg_rlimit_as = 1; |
1526 | } | 1532 | } |
1527 | else { | 1533 | else { |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 7bf372a14..99abce57f 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -840,6 +840,7 @@ int sandbox(void* sandbox_arg) { | |||
840 | // private mode | 840 | // private mode |
841 | //**************************** | 841 | //**************************** |
842 | if (arg_private) { | 842 | if (arg_private) { |
843 | EUID_USER(); | ||
843 | if (cfg.home_private) { // --private= | 844 | if (cfg.home_private) { // --private= |
844 | if (cfg.chrootdir) | 845 | if (cfg.chrootdir) |
845 | fwarning("private=directory feature is disabled in chroot\n"); | 846 | fwarning("private=directory feature is disabled in chroot\n"); |
@@ -858,6 +859,7 @@ int sandbox(void* sandbox_arg) { | |||
858 | } | 859 | } |
859 | else // --private | 860 | else // --private |
860 | fs_private(); | 861 | fs_private(); |
862 | EUID_ROOT(); | ||
861 | } | 863 | } |
862 | 864 | ||
863 | if (arg_private_dev) | 865 | if (arg_private_dev) |
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index 9670fe816..3d9bf9082 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c | |||
@@ -208,7 +208,8 @@ int seccomp_filter_drop(bool native) { | |||
208 | // - seccomp | 208 | // - seccomp |
209 | if (cfg.seccomp_list_drop == NULL) { | 209 | if (cfg.seccomp_list_drop == NULL) { |
210 | // default seccomp if error action is not changed | 210 | // default seccomp if error action is not changed |
211 | if (cfg.seccomp_list == NULL && arg_seccomp_error_action == DEFAULT_SECCOMP_ERROR_ACTION) { | 211 | if ((cfg.seccomp_list == NULL || cfg.seccomp_list[0] == '\0') |
212 | && arg_seccomp_error_action == DEFAULT_SECCOMP_ERROR_ACTION) { | ||
212 | if (arg_seccomp_block_secondary) | 213 | if (arg_seccomp_block_secondary) |
213 | seccomp_filter_block_secondary(); | 214 | seccomp_filter_block_secondary(); |
214 | else { | 215 | else { |
@@ -261,7 +262,7 @@ int seccomp_filter_drop(bool native) { | |||
261 | } | 262 | } |
262 | 263 | ||
263 | // build the seccomp filter as a regular user | 264 | // build the seccomp filter as a regular user |
264 | if (list) | 265 | if (list && list[0]) |
265 | if (arg_allow_debuggers) | 266 | if (arg_allow_debuggers) |
266 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, | 267 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, |
267 | PATH_FSECCOMP, command, "drop", filter, postexec_filter, list, "allow-debuggers"); | 268 | PATH_FSECCOMP, command, "drop", filter, postexec_filter, list, "allow-debuggers"); |
diff --git a/src/firejail/util.c b/src/firejail/util.c index 71dd84e8f..55998e6c3 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -31,6 +31,9 @@ | |||
31 | #include <sys/wait.h> | 31 | #include <sys/wait.h> |
32 | #include <limits.h> | 32 | #include <limits.h> |
33 | 33 | ||
34 | #include <string.h> | ||
35 | #include <ctype.h> | ||
36 | |||
34 | #include <fcntl.h> | 37 | #include <fcntl.h> |
35 | #ifndef O_PATH | 38 | #ifndef O_PATH |
36 | #define O_PATH 010000000 | 39 | #define O_PATH 010000000 |
@@ -50,6 +53,44 @@ | |||
50 | #define EMPTY_STRING ("") | 53 | #define EMPTY_STRING ("") |
51 | 54 | ||
52 | 55 | ||
56 | long long unsigned parse_arg_size(char *str) { | ||
57 | long long unsigned result = 0; | ||
58 | int len = strlen(str); | ||
59 | sscanf(str, "%llu", &result); | ||
60 | |||
61 | char suffix = *(str + len - 1); | ||
62 | if (!isdigit(suffix) && (suffix == 'k' || suffix == 'm' || suffix == 'g')) { | ||
63 | len -= 1; | ||
64 | } | ||
65 | |||
66 | /* checks for is value valid positive number */ | ||
67 | for (int i = 0; i < len; i++) { | ||
68 | if (!isdigit(*(str+i))) { | ||
69 | return 0; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | if (isdigit(suffix)) | ||
74 | return result; | ||
75 | |||
76 | switch (suffix) { | ||
77 | case 'k': | ||
78 | result *= 1024; | ||
79 | break; | ||
80 | case 'm': | ||
81 | result *= 1024 * 1024; | ||
82 | break; | ||
83 | case 'g': | ||
84 | result *= 1024 * 1024 * 1024; | ||
85 | break; | ||
86 | default: | ||
87 | result = 0; | ||
88 | break; | ||
89 | } | ||
90 | |||
91 | return result; | ||
92 | } | ||
93 | |||
53 | // send the error to /var/log/auth.log and exit after a small delay | 94 | // send the error to /var/log/auth.log and exit after a small delay |
54 | void errLogExit(char* fmt, ...) { | 95 | void errLogExit(char* fmt, ...) { |
55 | va_list args; | 96 | va_list args; |
@@ -329,7 +370,7 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m | |||
329 | } | 370 | } |
330 | 371 | ||
331 | // return -1 if error, 0 if no error | 372 | // return -1 if error, 0 if no error |
332 | void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) { | 373 | void copy_file_as_user(const char *srcname, const char *destname, mode_t mode) { |
333 | pid_t child = fork(); | 374 | pid_t child = fork(); |
334 | if (child < 0) | 375 | if (child < 0) |
335 | errExit("fork"); | 376 | errExit("fork"); |
@@ -337,8 +378,8 @@ void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid | |||
337 | // drop privileges | 378 | // drop privileges |
338 | drop_privs(0); | 379 | drop_privs(0); |
339 | 380 | ||
340 | // copy, set permissions and ownership | 381 | // copy, set permissions |
341 | int rv = copy_file(srcname, destname, uid, gid, mode); // already a regular user | 382 | int rv = copy_file(srcname, destname, -1, -1, mode); // already a regular user |
342 | if (rv) | 383 | if (rv) |
343 | fwarning("cannot copy %s\n", srcname); | 384 | fwarning("cannot copy %s\n", srcname); |
344 | #ifdef HAVE_GCOV | 385 | #ifdef HAVE_GCOV |
@@ -1190,6 +1231,7 @@ unsigned extract_timeout(const char *str) { | |||
1190 | } | 1231 | } |
1191 | 1232 | ||
1192 | void disable_file_or_dir(const char *fname) { | 1233 | void disable_file_or_dir(const char *fname) { |
1234 | assert(geteuid() == 0); | ||
1193 | assert(fname); | 1235 | assert(fname); |
1194 | 1236 | ||
1195 | EUID_USER(); | 1237 | EUID_USER(); |
diff --git a/src/firejail/x11.c b/src/firejail/x11.c index 0619ff380..896aa2fd3 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c | |||
@@ -1290,9 +1290,11 @@ void x11_xorg(void) { | |||
1290 | if (envar) { | 1290 | if (envar) { |
1291 | char *rp = realpath(envar, NULL); | 1291 | char *rp = realpath(envar, NULL); |
1292 | if (rp) { | 1292 | if (rp) { |
1293 | if (strcmp(rp, dest) != 0) | 1293 | if (strcmp(rp, dest) != 0) { |
1294 | // disable_file_or_dir returns with EUID 0 | 1294 | EUID_ROOT(); |
1295 | disable_file_or_dir(rp); | 1295 | disable_file_or_dir(rp); |
1296 | EUID_USER(); | ||
1297 | } | ||
1296 | free(rp); | 1298 | free(rp); |
1297 | } | 1299 | } |
1298 | } | 1300 | } |
diff --git a/src/jailcheck/jailcheck.h b/src/jailcheck/jailcheck.h index 32be1c978..be3104da3 100644 --- a/src/jailcheck/jailcheck.h +++ b/src/jailcheck/jailcheck.h | |||
@@ -53,6 +53,8 @@ void apparmor_test(pid_t pid); | |||
53 | // seccomp.c | 53 | // seccomp.c |
54 | void seccomp_test(pid_t pid); | 54 | void seccomp_test(pid_t pid); |
55 | 55 | ||
56 | // network.c | ||
57 | void network_test(void); | ||
56 | // utils.c | 58 | // utils.c |
57 | char *get_sudo_user(void); | 59 | char *get_sudo_user(void); |
58 | char *get_homedir(const char *user, uid_t *uid, gid_t *gid); | 60 | char *get_homedir(const char *user, uid_t *uid, gid_t *gid); |
diff --git a/src/jailcheck/main.c b/src/jailcheck/main.c index 4d642bf96..812ac5808 100644 --- a/src/jailcheck/main.c +++ b/src/jailcheck/main.c | |||
@@ -157,6 +157,7 @@ int main(int argc, char **argv) { | |||
157 | seccomp_test(pid); | 157 | seccomp_test(pid); |
158 | fflush(0); | 158 | fflush(0); |
159 | 159 | ||
160 | // filesystem tests | ||
160 | pid_t child = fork(); | 161 | pid_t child = fork(); |
161 | if (child == -1) | 162 | if (child == -1) |
162 | errExit("fork"); | 163 | errExit("fork"); |
@@ -185,6 +186,28 @@ int main(int argc, char **argv) { | |||
185 | } | 186 | } |
186 | int status; | 187 | int status; |
187 | wait(&status); | 188 | wait(&status); |
189 | |||
190 | // network test | ||
191 | child = fork(); | ||
192 | if (child == -1) | ||
193 | errExit("fork"); | ||
194 | if (child == 0) { | ||
195 | int rv = join_namespace(pid, "net"); | ||
196 | if (rv == 0) | ||
197 | network_test(); | ||
198 | else { | ||
199 | printf(" Error: I cannot join the process network stack\n"); | ||
200 | exit(1); | ||
201 | } | ||
202 | |||
203 | // drop privileges in order not to trigger cleanup() | ||
204 | if (setgid(user_gid) != 0) | ||
205 | errExit("setgid"); | ||
206 | if (setuid(user_uid) != 0) | ||
207 | errExit("setuid"); | ||
208 | return 0; | ||
209 | } | ||
210 | wait(&status); | ||
188 | } | 211 | } |
189 | } | 212 | } |
190 | 213 | ||
diff --git a/src/jailcheck/network.c b/src/jailcheck/network.c new file mode 100644 index 000000000..636344e77 --- /dev/null +++ b/src/jailcheck/network.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2021 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | #include "jailcheck.h" | ||
21 | #include <netdb.h> | ||
22 | #include <arpa/inet.h> | ||
23 | #include <ifaddrs.h> | ||
24 | #include <net/if.h> | ||
25 | #include <linux/connector.h> | ||
26 | #include <linux/netlink.h> | ||
27 | #include <linux/if_link.h> | ||
28 | #include <linux/sockios.h> | ||
29 | #include <sys/ioctl.h> | ||
30 | |||
31 | |||
32 | void network_test(void) { | ||
33 | // I am root running in a network namespace | ||
34 | struct ifaddrs *ifaddr, *ifa; | ||
35 | int found = 0; | ||
36 | |||
37 | // walk through the linked list | ||
38 | if (getifaddrs(&ifaddr) == -1) | ||
39 | errExit("getifaddrs"); | ||
40 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { | ||
41 | if (strcmp(ifa->ifa_name, "lo") == 0) | ||
42 | continue; | ||
43 | found = 1; | ||
44 | break; | ||
45 | } | ||
46 | |||
47 | freeifaddrs(ifaddr); | ||
48 | |||
49 | if (found) | ||
50 | printf(" Networking: enabled\n"); | ||
51 | else | ||
52 | printf(" Networking: disabled\n"); | ||
53 | } | ||
54 | |||
55 | |||
56 | |||
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 6f3bef7f2..db58e0910 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt | |||
@@ -420,7 +420,7 @@ Make directory or file read-only. | |||
420 | Make directory or file read-write. | 420 | Make directory or file read-write. |
421 | .TP | 421 | .TP |
422 | \fBtmpfs directory | 422 | \fBtmpfs directory |
423 | Mount an empty tmpfs filesystem on top of directory. This option is available only when running the sandbox as root. | 423 | Mount an empty tmpfs filesystem on top of directory. Directories outside user home or not owned by the user are not allowed. Sandboxes running as root are exempt from these restrictions. |
424 | .TP | 424 | .TP |
425 | \fBtracelog | 425 | \fBtracelog |
426 | Blacklist violations logged to syslog. | 426 | Blacklist violations logged to syslog. |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 3212a88e4..0462705c0 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -2129,6 +2129,7 @@ $ firejail --read-only=~/test --read-write=~/test/a | |||
2129 | .TP | 2129 | .TP |
2130 | \fB\-\-rlimit-as=number | 2130 | \fB\-\-rlimit-as=number |
2131 | Set the maximum size of the process's virtual memory (address space) in bytes. | 2131 | Set the maximum size of the process's virtual memory (address space) in bytes. |
2132 | Use k(ilobyte), m(egabyte) or g(igabyte) for size suffix (base 1024). | ||
2132 | 2133 | ||
2133 | .TP | 2134 | .TP |
2134 | \fB\-\-rlimit-cpu=number | 2135 | \fB\-\-rlimit-cpu=number |
@@ -2142,6 +2143,7 @@ track of CPU seconds for each process independently. | |||
2142 | .TP | 2143 | .TP |
2143 | \fB\-\-rlimit-fsize=number | 2144 | \fB\-\-rlimit-fsize=number |
2144 | Set the maximum file size that can be created by a process. | 2145 | Set the maximum file size that can be created by a process. |
2146 | Use k(ilobyte), m(egabyte) or g(igabyte) for size suffix (base 1024). | ||
2145 | .TP | 2147 | .TP |
2146 | \fB\-\-rlimit-nofile=number | 2148 | \fB\-\-rlimit-nofile=number |
2147 | Set the maximum number of files that can be opened by a process. | 2149 | Set the maximum number of files that can be opened by a process. |
@@ -2176,7 +2178,7 @@ $ firejail \-\-net=eth0 \-\-scan | |||
2176 | .TP | 2178 | .TP |
2177 | \fB\-\-seccomp | 2179 | \fB\-\-seccomp |
2178 | Enable seccomp filter and blacklist the syscalls in the default list, | 2180 | Enable seccomp filter and blacklist the syscalls in the default list, |
2179 | which is @default-nodebuggers unless allow-debuggers is specified, | 2181 | which is @default-nodebuggers unless \-\-allow-debuggers is specified, |
2180 | then it is @default. | 2182 | then it is @default. |
2181 | 2183 | ||
2182 | .br | 2184 | .br |
@@ -2187,18 +2189,13 @@ system call groups are defined: @aio, @basic-io, @chown, @clock, | |||
2187 | @network-io, @obsolete, @privileged, @process, @raw-io, @reboot, | 2189 | @network-io, @obsolete, @privileged, @process, @raw-io, @reboot, |
2188 | @resources, @setuid, @swap, @sync, @system-service and @timer. | 2190 | @resources, @setuid, @swap, @sync, @system-service and @timer. |
2189 | More information about groups can be found in /usr/share/doc/firejail/syscalls.txt | 2191 | More information about groups can be found in /usr/share/doc/firejail/syscalls.txt |
2190 | 2192 | .br | |
2191 | In addition, a system call can be specified by its number instead of | ||
2192 | name with prefix $, so for example $165 would be equal to mount on i386. | ||
2193 | Exceptions can be allowed with prefix !. | ||
2194 | 2193 | ||
2195 | .br | 2194 | .br |
2196 | System architecture is strictly imposed only if flag | 2195 | System architecture is strictly imposed only if flag |
2197 | \-\-seccomp.block-secondary is used. The filter is applied at run time | 2196 | \-\-seccomp.block-secondary is used. The filter is applied at run time |
2198 | only if the correct architecture was detected. For the case of I386 | 2197 | only if the correct architecture was detected. For the case of I386 |
2199 | and AMD64 both 32-bit and 64-bit filters are installed. On a 64 bit | 2198 | and AMD64 both 32-bit and 64-bit filters are installed. |
2200 | architecture, an additional filter for 32 bit system calls can be | ||
2201 | installed with \-\-seccomp.32. | ||
2202 | .br | 2199 | .br |
2203 | 2200 | ||
2204 | .br | 2201 | .br |
@@ -2209,11 +2206,18 @@ Firejail will print seccomp violations to the audit log if the kernel was compil | |||
2209 | Example: | 2206 | Example: |
2210 | .br | 2207 | .br |
2211 | $ firejail \-\-seccomp | 2208 | $ firejail \-\-seccomp |
2209 | .br | ||
2210 | |||
2211 | .br | ||
2212 | The default list can be customized, see \-\-seccomp= for a description. It can be customized | ||
2213 | also globally in /etc/firejail/firejail.config file. | ||
2214 | |||
2212 | .TP | 2215 | .TP |
2213 | \fB\-\-seccomp=syscall,@group,!syscall2 | 2216 | \fB\-\-seccomp=syscall,@group,!syscall2 |
2214 | Enable seccomp filter, whitelist "syscall2", but blacklist the default | 2217 | Enable seccomp filter, blacklist the default list and the syscalls or syscall groups |
2215 | list and the syscalls or syscall groups specified by the | 2218 | specified by the command, but don't blacklist "syscall2". On a 64 bit |
2216 | command. | 2219 | architecture, an additional filter for 32 bit system calls can be |
2220 | installed with \-\-seccomp.32. | ||
2217 | .br | 2221 | .br |
2218 | 2222 | ||
2219 | .br | 2223 | .br |
@@ -2223,6 +2227,13 @@ $ firejail \-\-seccomp=utime,utimensat,utimes firefox | |||
2223 | .br | 2227 | .br |
2224 | $ firejail \-\-seccomp=@clock,mkdir,unlinkat transmission-gtk | 2228 | $ firejail \-\-seccomp=@clock,mkdir,unlinkat transmission-gtk |
2225 | .br | 2229 | .br |
2230 | $ firejail '\-\-seccomp=@ipc,!pipe,!pipe2' audacious | ||
2231 | .br | ||
2232 | |||
2233 | .br | ||
2234 | Syscalls can be specified by their number if prefix $ is added, | ||
2235 | so for example $165 would be equal to mount on i386. | ||
2236 | .br | ||
2226 | 2237 | ||
2227 | .br | 2238 | .br |
2228 | Instead of dropping the syscall by returning EPERM, another error | 2239 | Instead of dropping the syscall by returning EPERM, another error |
@@ -2235,6 +2246,7 @@ by using \fBsyscall:kill\fR syntax, or the attempt may be logged with | |||
2235 | 2246 | ||
2236 | .br | 2247 | .br |
2237 | Example: | 2248 | Example: |
2249 | .br | ||
2238 | $ firejail \-\-seccomp=unlinkat:ENOENT,utimensat,utimes | 2250 | $ firejail \-\-seccomp=unlinkat:ENOENT,utimensat,utimes |
2239 | .br | 2251 | .br |
2240 | Parent pid 10662, child pid 10663 | 2252 | Parent pid 10662, child pid 10663 |
@@ -2243,9 +2255,13 @@ Child process initialized | |||
2243 | .br | 2255 | .br |
2244 | $ touch testfile | 2256 | $ touch testfile |
2245 | .br | 2257 | .br |
2258 | $ ls testfile | ||
2259 | .br | ||
2260 | testfile | ||
2261 | .br | ||
2246 | $ rm testfile | 2262 | $ rm testfile |
2247 | .br | 2263 | .br |
2248 | rm: cannot remove `testfile': Operation not permitted | 2264 | rm: cannot remove `testfile': No such file or directory |
2249 | .br | 2265 | .br |
2250 | 2266 | ||
2251 | .br | 2267 | .br |
@@ -2258,7 +2274,7 @@ filters. | |||
2258 | .br | 2274 | .br |
2259 | Example: | 2275 | Example: |
2260 | .br | 2276 | .br |
2261 | $ firejail \-\-noprofile \-\-shell=none \-\-seccomp=execve bash | 2277 | $ firejail \-\-noprofile \-\-shell=none \-\-seccomp=execve sh |
2262 | .br | 2278 | .br |
2263 | Parent pid 32751, child pid 32752 | 2279 | Parent pid 32751, child pid 32752 |
2264 | .br | 2280 | .br |
@@ -2270,8 +2286,7 @@ Child process initialized in 46.44 ms | |||
2270 | .br | 2286 | .br |
2271 | $ ls | 2287 | $ ls |
2272 | .br | 2288 | .br |
2273 | Bad system call | 2289 | Operation not permitted |
2274 | .br | ||
2275 | 2290 | ||
2276 | .TP | 2291 | .TP |
2277 | \fB\-\-seccomp.block-secondary | 2292 | \fB\-\-seccomp.block-secondary |
@@ -2315,15 +2330,15 @@ Child process initialized | |||
2315 | .br | 2330 | .br |
2316 | $ touch testfile | 2331 | $ touch testfile |
2317 | .br | 2332 | .br |
2333 | $ ls testfile | ||
2334 | .br | ||
2335 | testfile | ||
2336 | .br | ||
2318 | $ rm testfile | 2337 | $ rm testfile |
2319 | .br | 2338 | .br |
2320 | rm: cannot remove `testfile': Operation not permitted | 2339 | rm: cannot remove `testfile': No such file or directory |
2321 | .br | 2340 | .br |
2322 | 2341 | ||
2323 | |||
2324 | |||
2325 | |||
2326 | |||
2327 | .TP | 2342 | .TP |
2328 | \fB\-\-seccomp.keep=syscall,@group,!syscall2 | 2343 | \fB\-\-seccomp.keep=syscall,@group,!syscall2 |
2329 | Enable seccomp filter, blacklist all syscall not listed and "syscall2". | 2344 | Enable seccomp filter, blacklist all syscall not listed and "syscall2". |
@@ -2566,14 +2581,13 @@ Kill the sandbox automatically after the time has elapsed. The time is specified | |||
2566 | $ firejail \-\-timeout=01:30:00 firefox | 2581 | $ firejail \-\-timeout=01:30:00 firefox |
2567 | .TP | 2582 | .TP |
2568 | \fB\-\-tmpfs=dirname | 2583 | \fB\-\-tmpfs=dirname |
2569 | Mount a writable tmpfs filesystem on directory dirname. This option is available only when running the sandbox as root. | 2584 | Mount a writable tmpfs filesystem on directory dirname. Directories outside user home or not owned by the user are not allowed. Sandboxes running as root are exempt from these restrictions. File globbing is supported, see \fBFILE GLOBBING\fR section for more details. |
2570 | File globbing is supported, see \fBFILE GLOBBING\fR section for more details. | ||
2571 | .br | 2585 | .br |
2572 | 2586 | ||
2573 | .br | 2587 | .br |
2574 | Example: | 2588 | Example: |
2575 | .br | 2589 | .br |
2576 | # firejail \-\-tmpfs=/var | 2590 | $ firejail \-\-tmpfs=~/.local/share |
2577 | .TP | 2591 | .TP |
2578 | \fB\-\-top | 2592 | \fB\-\-top |
2579 | Monitor the most CPU-intensive sandboxes, see \fBMONITORING\fR section for more details. | 2593 | Monitor the most CPU-intensive sandboxes, see \fBMONITORING\fR section for more details. |
diff --git a/src/man/jailcheck.txt b/src/man/jailcheck.txt index c80e305cc..483f47fb9 100644 --- a/src/man/jailcheck.txt +++ b/src/man/jailcheck.txt | |||
@@ -23,6 +23,8 @@ them from inside the sandbox. | |||
23 | .TP | 23 | .TP |
24 | \fB5. Seccomp test | 24 | \fB5. Seccomp test |
25 | .TP | 25 | .TP |
26 | \fB6. Networking test | ||
27 | .TP | ||
26 | The program is started as root using sudo. | 28 | The program is started as root using sudo. |
27 | 29 | ||
28 | .SH OPTIONS | 30 | .SH OPTIONS |
@@ -56,6 +58,8 @@ $ sudo jailcheck | |||
56 | .br | 58 | .br |
57 | Warning: I can run programs in /home/netblue | 59 | Warning: I can run programs in /home/netblue |
58 | .br | 60 | .br |
61 | Networking: disabled | ||
62 | .br | ||
59 | 63 | ||
60 | .br | 64 | .br |
61 | 2055:netblue::firejail /usr/bin/ssh -X netblue@x.y.z.net | 65 | 2055:netblue::firejail /usr/bin/ssh -X netblue@x.y.z.net |
@@ -64,12 +68,16 @@ $ sudo jailcheck | |||
64 | .br | 68 | .br |
65 | Warning: I can read ~/.ssh | 69 | Warning: I can read ~/.ssh |
66 | .br | 70 | .br |
71 | Networking: enabled | ||
72 | .br | ||
67 | 73 | ||
68 | .br | 74 | .br |
69 | 2186:netblue:libreoffice:firejail --appimage /opt/LibreOffice-fresh.appimage | 75 | 2186:netblue:libreoffice:firejail --appimage /opt/LibreOffice-fresh.appimage |
70 | .br | 76 | .br |
71 | Virtual dirs: /tmp, /var/tmp, /dev, | 77 | Virtual dirs: /tmp, /var/tmp, /dev, |
72 | .br | 78 | .br |
79 | Networking: enabled | ||
80 | .br | ||
73 | 81 | ||
74 | .br | 82 | .br |
75 | 26090:netblue::/usr/bin/firejail /opt/firefox/firefox | 83 | 26090:netblue::/usr/bin/firejail /opt/firefox/firefox |
@@ -78,6 +86,8 @@ $ sudo jailcheck | |||
78 | .br | 86 | .br |
79 | /run/user/1000, | 87 | /run/user/1000, |
80 | .br | 88 | .br |
89 | Networking: enabled | ||
90 | .br | ||
81 | 91 | ||
82 | .br | 92 | .br |
83 | 26160:netblue:tor:firejail --private=~/tor-browser_en-US ./start-tor | 93 | 26160:netblue:tor:firejail --private=~/tor-browser_en-US ./start-tor |
@@ -90,6 +100,8 @@ $ sudo jailcheck | |||
90 | .br | 100 | .br |
91 | Warning: I can run programs in /home/netblue | 101 | Warning: I can run programs in /home/netblue |
92 | .br | 102 | .br |
103 | Networking: enabled | ||
104 | .br | ||
93 | 105 | ||
94 | 106 | ||
95 | .SH LICENSE | 107 | .SH LICENSE |
diff --git a/test/environment/rlimit-bad-profile.exp b/test/environment/rlimit-bad-profile.exp index b838f83f4..b1572afb6 100755 --- a/test/environment/rlimit-bad-profile.exp +++ b/test/environment/rlimit-bad-profile.exp | |||
@@ -11,7 +11,7 @@ match_max 100000 | |||
11 | send -- "firejail --profile=rlimit-bad1.profile\r" | 11 | send -- "firejail --profile=rlimit-bad1.profile\r" |
12 | expect { | 12 | expect { |
13 | timeout {puts "TESTING ERROR 4\n";exit} | 13 | timeout {puts "TESTING ERROR 4\n";exit} |
14 | "invalid rlimit" | 14 | "invalid rlimit-fsize in profile file. Only use positive numbers and k, m or g suffix." |
15 | } | 15 | } |
16 | after 100 | 16 | after 100 |
17 | 17 | ||
diff --git a/test/environment/rlimit-bad.exp b/test/environment/rlimit-bad.exp index 3a82ded9b..c05e14b97 100755 --- a/test/environment/rlimit-bad.exp +++ b/test/environment/rlimit-bad.exp | |||
@@ -10,7 +10,7 @@ match_max 100000 | |||
10 | send -- "firejail --rlimit-fsize=-1024\r" | 10 | send -- "firejail --rlimit-fsize=-1024\r" |
11 | expect { | 11 | expect { |
12 | timeout {puts "TESTING ERROR 0\n";exit} | 12 | timeout {puts "TESTING ERROR 0\n";exit} |
13 | "invalid rlimit" | 13 | "invalid rlimit-fsize. Only use positive numbers and k, m or g suffix." |
14 | } | 14 | } |
15 | after 100 | 15 | after 100 |
16 | 16 | ||
diff --git a/test/fs/fscheck-tmpfs.exp b/test/fs/fscheck-tmpfs.exp index 8dd08aa72..78b6efb76 100755 --- a/test/fs/fscheck-tmpfs.exp +++ b/test/fs/fscheck-tmpfs.exp | |||
@@ -41,7 +41,7 @@ after 500 | |||
41 | send -- "firejail --noprofile --tmpfs=/tmp/fjtest-dir\r" | 41 | send -- "firejail --noprofile --tmpfs=/tmp/fjtest-dir\r" |
42 | expect { | 42 | expect { |
43 | timeout {puts "TESTING ERROR 5\n";exit} | 43 | timeout {puts "TESTING ERROR 5\n";exit} |
44 | "Error" | 44 | "Warning: you are not allowed to mount a tmpfs" |
45 | } | 45 | } |
46 | after 500 | 46 | after 500 |
47 | 47 | ||