diff options
author | 2018-12-15 17:00:49 +0100 | |
---|---|---|
committer | 2018-12-15 17:37:22 +0100 | |
commit | 89fa2a7562e84338d88ea83777861f00e545135d (patch) | |
tree | 78e9ab303fb28d9b94542ee96fbdb51ca6e8982c | |
parent | join: check prctl return value (diff) | |
download | firejail-89fa2a7562e84338d88ea83777861f00e545135d.tar.gz firejail-89fa2a7562e84338d88ea83777861f00e545135d.tar.zst firejail-89fa2a7562e84338d88ea83777861f00e545135d.zip |
enforce nonewprivs instead of seccomp for chroot sandboxes
currently users are able to specify a seccomp filter of their
choosing, leaving the real defense to nonewprivs anyway.
-rw-r--r-- | src/firejail/main.c | 25 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 46 | ||||
-rw-r--r-- | src/firejail/seccomp.c | 6 | ||||
-rw-r--r-- | src/man/firejail.txt | 12 |
4 files changed, 43 insertions, 46 deletions
diff --git a/src/firejail/main.c b/src/firejail/main.c index f35b2a925..9aff4e4e5 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -866,7 +866,6 @@ int main(int argc, char **argv) { | |||
866 | int lockfd_directory = -1; | 866 | int lockfd_directory = -1; |
867 | int option_cgroup = 0; | 867 | int option_cgroup = 0; |
868 | int custom_profile = 0; // custom profile loaded | 868 | int custom_profile = 0; // custom profile loaded |
869 | int arg_seccomp_cmdline = 0; // seccomp requested on command line (used to break out of --chroot) | ||
870 | int arg_caps_cmdline = 0; // caps requested on command line (used to break out of --chroot) | 869 | int arg_caps_cmdline = 0; // caps requested on command line (used to break out of --chroot) |
871 | 870 | ||
872 | // drop permissions by default and rise them when required | 871 | // drop permissions by default and rise them when required |
@@ -1153,7 +1152,6 @@ int main(int argc, char **argv) { | |||
1153 | } | 1152 | } |
1154 | arg_seccomp = 1; | 1153 | arg_seccomp = 1; |
1155 | cfg.seccomp_list = seccomp_check_list(argv[i] + 10); | 1154 | cfg.seccomp_list = seccomp_check_list(argv[i] + 10); |
1156 | arg_seccomp_cmdline = 1; | ||
1157 | } | 1155 | } |
1158 | else | 1156 | else |
1159 | exit_err_feature("seccomp"); | 1157 | exit_err_feature("seccomp"); |
@@ -1166,7 +1164,6 @@ int main(int argc, char **argv) { | |||
1166 | } | 1164 | } |
1167 | arg_seccomp = 1; | 1165 | arg_seccomp = 1; |
1168 | cfg.seccomp_list_drop = seccomp_check_list(argv[i] + 15); | 1166 | cfg.seccomp_list_drop = seccomp_check_list(argv[i] + 15); |
1169 | arg_seccomp_cmdline = 1; | ||
1170 | } | 1167 | } |
1171 | else | 1168 | else |
1172 | exit_err_feature("seccomp"); | 1169 | exit_err_feature("seccomp"); |
@@ -1179,7 +1176,6 @@ int main(int argc, char **argv) { | |||
1179 | } | 1176 | } |
1180 | arg_seccomp = 1; | 1177 | arg_seccomp = 1; |
1181 | cfg.seccomp_list_keep = seccomp_check_list(argv[i] + 15); | 1178 | cfg.seccomp_list_keep = seccomp_check_list(argv[i] + 15); |
1182 | arg_seccomp_cmdline = 1; | ||
1183 | } | 1179 | } |
1184 | else | 1180 | else |
1185 | exit_err_feature("seccomp"); | 1181 | exit_err_feature("seccomp"); |
@@ -2278,12 +2274,21 @@ int main(int argc, char **argv) { | |||
2278 | } | 2274 | } |
2279 | EUID_ASSERT(); | 2275 | EUID_ASSERT(); |
2280 | 2276 | ||
2281 | // exit for --chroot sandboxes when secomp or caps are explicitly specified on command line | 2277 | // exit chroot, overlay and appimage sandboxes when caps are explicitly specified on command line |
2282 | if (getuid() != 0 && cfg.chrootdir && (arg_seccomp_cmdline || arg_caps_cmdline)) { | 2278 | if (getuid() != 0 && arg_caps_cmdline) { |
2283 | fprintf(stderr, "Error: for chroot sandboxes, default seccomp and capabilities filters are\n" | 2279 | char *opt = NULL; |
2284 | "enabled by default. Please remove all --seccomp and --caps options from the\n" | 2280 | if (cfg.chrootdir) |
2285 | "command line.\n"); | 2281 | opt = "chroot"; |
2286 | exit(1); | 2282 | else if (arg_overlay) |
2283 | opt = "overlay"; | ||
2284 | else if (arg_appimage) | ||
2285 | opt = "appimage"; | ||
2286 | |||
2287 | if (opt) { | ||
2288 | fprintf(stderr, "Error: all capabilities are dropped for %s by default.\n" | ||
2289 | "Please remove --caps options from the command line.\n", opt); | ||
2290 | exit(1); | ||
2291 | } | ||
2287 | } | 2292 | } |
2288 | 2293 | ||
2289 | // prog_index could still be -1 if no program was specified | 2294 | // prog_index could still be -1 if no program was specified |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 2113ef70f..6a9977455 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -39,6 +39,9 @@ | |||
39 | #ifndef PR_SET_NO_NEW_PRIVS | 39 | #ifndef PR_SET_NO_NEW_PRIVS |
40 | # define PR_SET_NO_NEW_PRIVS 38 | 40 | # define PR_SET_NO_NEW_PRIVS 38 |
41 | #endif | 41 | #endif |
42 | #ifndef PR_GET_NO_NEW_PRIVS | ||
43 | # define PR_GET_NO_NEW_PRIVS 39 | ||
44 | #endif | ||
42 | 45 | ||
43 | #ifdef HAVE_APPARMOR | 46 | #ifdef HAVE_APPARMOR |
44 | #include <sys/apparmor.h> | 47 | #include <sys/apparmor.h> |
@@ -46,10 +49,7 @@ | |||
46 | #include <syscall.h> | 49 | #include <syscall.h> |
47 | 50 | ||
48 | 51 | ||
49 | #ifdef HAVE_SECCOMP | 52 | static int force_nonewprivs = 0; |
50 | int enforce_seccomp = 0; | ||
51 | #endif | ||
52 | |||
53 | 53 | ||
54 | static int monitored_pid = 0; | 54 | static int monitored_pid = 0; |
55 | static void sandbox_handler(int sig){ | 55 | static void sandbox_handler(int sig){ |
@@ -539,23 +539,17 @@ void start_application(int no_sandbox, FILE *fp) { | |||
539 | } | 539 | } |
540 | 540 | ||
541 | static void enforce_filters(void) { | 541 | static void enforce_filters(void) { |
542 | // force default seccomp inside the chroot, no keep or drop list | 542 | // enforce NO_NEW_PRIVS |
543 | // the list build on top of the default drop list is kept intact | ||
544 | arg_nonewprivs = 1; | 543 | arg_nonewprivs = 1; |
545 | arg_seccomp = 1; | 544 | force_nonewprivs = 1; |
546 | #ifdef HAVE_SECCOMP | ||
547 | enforce_seccomp = 1; | ||
548 | #endif | ||
549 | 545 | ||
550 | // disable all capabilities | 546 | // disable all capabilities |
551 | if (arg_caps_default_filter || arg_caps_list) | 547 | fmessage("\n** Warning: dropping all Linux capabilities **\n"); |
552 | fwarning("all capabilities disabled for a regular user in chroot\n"); | ||
553 | arg_caps_drop_all = 1; | 548 | arg_caps_drop_all = 1; |
554 | 549 | ||
555 | // drop all supplementary groups; /etc/group file inside chroot | 550 | // drop all supplementary groups; /etc/group file inside chroot |
556 | // is controlled by a regular usr | 551 | // is controlled by a regular usr |
557 | arg_nogroups = 1; | 552 | arg_nogroups = 1; |
558 | fmessage("\n** Warning: dropping all Linux capabilities **\n"); | ||
559 | } | 553 | } |
560 | 554 | ||
561 | int sandbox(void* sandbox_arg) { | 555 | int sandbox(void* sandbox_arg) { |
@@ -754,24 +748,17 @@ int sandbox(void* sandbox_arg) { | |||
754 | 748 | ||
755 | // need ld.so.preload if tracing or seccomp with any non-default lists | 749 | // need ld.so.preload if tracing or seccomp with any non-default lists |
756 | bool need_preload = arg_trace || arg_tracelog || arg_seccomp_postexec; | 750 | bool need_preload = arg_trace || arg_tracelog || arg_seccomp_postexec; |
757 | // for --appimage, --chroot and --overlay* we replace the seccomp filter with the default one | 751 | // for --appimage, --chroot and --overlay* we force NO_NEW_PRIVS |
758 | // we also drop all capabilities | 752 | // and drop all capabilities |
759 | if (getuid() != 0 && (arg_appimage || cfg.chrootdir || arg_overlay)) { | 753 | if (getuid() != 0 && (arg_appimage || cfg.chrootdir || arg_overlay)) { |
760 | enforce_filters(); | 754 | enforce_filters(); |
761 | need_preload = arg_trace || arg_tracelog; | 755 | need_preload = arg_trace || arg_tracelog; |
762 | arg_seccomp = 1; | ||
763 | } | 756 | } |
764 | 757 | ||
765 | // trace pre-install | 758 | // trace pre-install |
766 | if (need_preload) | 759 | if (need_preload) |
767 | fs_trace_preload(); | 760 | fs_trace_preload(); |
768 | 761 | ||
769 | // state of nonewprivs | ||
770 | save_nonewprivs(); | ||
771 | |||
772 | // save original umask | ||
773 | save_umask(); | ||
774 | |||
775 | // store hosts file | 762 | // store hosts file |
776 | if (cfg.hosts_file) | 763 | if (cfg.hosts_file) |
777 | fs_store_hosts_file(); | 764 | fs_store_hosts_file(); |
@@ -1043,9 +1030,15 @@ int sandbox(void* sandbox_arg) { | |||
1043 | if (arg_x11_xorg) | 1030 | if (arg_x11_xorg) |
1044 | x11_xorg(); | 1031 | x11_xorg(); |
1045 | 1032 | ||
1033 | // save original umask | ||
1034 | save_umask(); | ||
1035 | |||
1046 | //**************************** | 1036 | //**************************** |
1047 | // set security filters | 1037 | // set security filters |
1048 | //**************************** | 1038 | //**************************** |
1039 | // save state of nonewprivs | ||
1040 | save_nonewprivs(); | ||
1041 | |||
1049 | // set capabilities | 1042 | // set capabilities |
1050 | set_caps(); | 1043 | set_caps(); |
1051 | 1044 | ||
@@ -1145,8 +1138,13 @@ int sandbox(void* sandbox_arg) { | |||
1145 | if (arg_nonewprivs) { | 1138 | if (arg_nonewprivs) { |
1146 | prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | 1139 | prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); |
1147 | 1140 | ||
1148 | if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) != 1) | 1141 | if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) != 1) { |
1149 | fwarning("NO_NEW_PRIVS disabled, it requires a Linux kernel version 3.5 or newer.\n"); | 1142 | fwarning("cannot set NO_NEW_PRIVS, it requires a Linux kernel version 3.5 or newer.\n"); |
1143 | if (force_nonewprivs) { | ||
1144 | fprintf(stderr, "Error: NO_NEW_PRIVS required for this sandbox, exiting ...\n"); | ||
1145 | exit(1); | ||
1146 | } | ||
1147 | } | ||
1150 | else if (arg_debug) | 1148 | else if (arg_debug) |
1151 | printf("NO_NEW_PRIVS set\n"); | 1149 | printf("NO_NEW_PRIVS set\n"); |
1152 | } | 1150 | } |
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index 7be7b3950..974e36ba7 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c | |||
@@ -31,7 +31,6 @@ typedef struct filter_list { | |||
31 | 31 | ||
32 | static FilterList *filter_list_head = NULL; | 32 | static FilterList *filter_list_head = NULL; |
33 | static int err_printed = 0; | 33 | static int err_printed = 0; |
34 | extern int enforce_seccomp; | ||
35 | 34 | ||
36 | char *seccomp_check_list(const char *str) { | 35 | char *seccomp_check_list(const char *str) { |
37 | assert(str); | 36 | assert(str); |
@@ -74,11 +73,6 @@ int seccomp_install_filters(void) { | |||
74 | 73 | ||
75 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &fl->prog)) { | 74 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &fl->prog)) { |
76 | 75 | ||
77 | if (enforce_seccomp) { | ||
78 | fprintf(stderr, "Error: a seccomp-enabled Linux kernel is required, exiting...\n"); | ||
79 | exit(1); | ||
80 | } | ||
81 | |||
82 | if (!err_printed) | 76 | if (!err_printed) |
83 | fwarning("seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); | 77 | fwarning("seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); |
84 | err_printed = 1; | 78 | err_printed = 1; |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 66663be35..9c1133756 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -100,8 +100,8 @@ $ firejail --allusers | |||
100 | Enable AppArmor confinement. For more information, please see \fBAPPARMOR\fR section below. | 100 | Enable AppArmor confinement. For more information, please see \fBAPPARMOR\fR section below. |
101 | .TP | 101 | .TP |
102 | \fB\-\-appimage | 102 | \fB\-\-appimage |
103 | Sandbox an AppImage (https://appimage.org/) application. If the sandbox is started as a | 103 | Sandbox an AppImage (https://appimage.org/) application. If the sandbox is started |
104 | regular user, default seccomp and capabilities filters are enabled. | 104 | as a regular user, nonewprivs and a default capabilities filter are enabled. |
105 | .br | 105 | .br |
106 | 106 | ||
107 | .br | 107 | .br |
@@ -275,7 +275,7 @@ Example: | |||
275 | \fB\-\-chroot=dirname | 275 | \fB\-\-chroot=dirname |
276 | Chroot the sandbox into a root filesystem. Unlike the regular filesystem container, | 276 | Chroot the sandbox into a root filesystem. Unlike the regular filesystem container, |
277 | the system directories are mounted read-write. If the sandbox is started as a | 277 | the system directories are mounted read-write. If the sandbox is started as a |
278 | regular user, default seccomp and capabilities filters are enabled. | 278 | regular user, nonewprivs and a default capabilities filter are enabled. |
279 | .br | 279 | .br |
280 | 280 | ||
281 | .br | 281 | .br |
@@ -1287,7 +1287,7 @@ Similar to \-\-output, but stderr is also stored. | |||
1287 | Mount a filesystem overlay on top of the current filesystem. Unlike the regular filesystem container, | 1287 | Mount a filesystem overlay on top of the current filesystem. Unlike the regular filesystem container, |
1288 | the system directories are mounted read-write. All filesystem modifications go into the overlay. | 1288 | the system directories are mounted read-write. All filesystem modifications go into the overlay. |
1289 | Directories /run, /tmp and /dev are not covered by the overlay. The overlay is stored in $HOME/.firejail/<PID> directory. | 1289 | Directories /run, /tmp and /dev are not covered by the overlay. The overlay is stored in $HOME/.firejail/<PID> directory. |
1290 | If the sandbox is started as a regular user, default seccomp and capabilities filters are enabled. | 1290 | If the sandbox is started as a regular user, nonewprivs and a default capabilities filter are enabled. |
1291 | .br | 1291 | .br |
1292 | 1292 | ||
1293 | .br | 1293 | .br |
@@ -1307,7 +1307,7 @@ Mount a filesystem overlay on top of the current filesystem. Unlike the regular | |||
1307 | the system directories are mounted read-write. All filesystem modifications go into the overlay. | 1307 | the system directories are mounted read-write. All filesystem modifications go into the overlay. |
1308 | Directories /run, /tmp and /dev are not covered by the overlay. The overlay is stored in $HOME/.firejail/<NAME> directory. | 1308 | Directories /run, /tmp and /dev are not covered by the overlay. The overlay is stored in $HOME/.firejail/<NAME> directory. |
1309 | The created overlay can be reused between multiple sessions. | 1309 | The created overlay can be reused between multiple sessions. |
1310 | If the sandbox is started as a regular user, default seccomp and capabilities filters are enabled. | 1310 | If the sandbox is started as a regular user, nonewprivs and a default capabilities filter are enabled. |
1311 | .br | 1311 | .br |
1312 | 1312 | ||
1313 | .br | 1313 | .br |
@@ -1325,7 +1325,7 @@ $ firejail \-\-overlay-named=jail1 firefox | |||
1325 | \fB\-\-overlay-tmpfs | 1325 | \fB\-\-overlay-tmpfs |
1326 | Mount a filesystem overlay on top of the current filesystem. All filesystem modifications | 1326 | Mount a filesystem overlay on top of the current filesystem. All filesystem modifications |
1327 | are discarded when the sandbox is closed. Directories /run, /tmp and /dev are not covered by the overlay. | 1327 | are discarded when the sandbox is closed. Directories /run, /tmp and /dev are not covered by the overlay. |
1328 | If the sandbox is started as a regular user, default seccomp and capabilities filters are enabled. | 1328 | If the sandbox is started as a regular user, nonewprivs and a default capabilities filter are enabled. |
1329 | .br | 1329 | .br |
1330 | 1330 | ||
1331 | .br | 1331 | .br |