diff options
-rw-r--r-- | src/firejail/sandbox.c | 193 | ||||
-rwxr-xr-x | test/fs_chroot.exp | 2 | ||||
-rwxr-xr-x | test/ignore.exp | 2 | ||||
-rwxr-xr-x | test/option-trace.exp | 10 | ||||
-rwxr-xr-x | test/pid.exp | 2 | ||||
-rwxr-xr-x | test/trace.exp | 29 |
6 files changed, 150 insertions, 88 deletions
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 81d09ed34..582a4f520 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #include <sys/prctl.h> | 25 | #include <sys/prctl.h> |
26 | #include <sys/time.h> | 26 | #include <sys/time.h> |
27 | #include <sys/resource.h> | 27 | #include <sys/resource.h> |
28 | #include <sys/types.h> | ||
29 | #include <dirent.h> | ||
28 | 30 | ||
29 | #include <sched.h> | 31 | #include <sched.h> |
30 | #ifndef CLONE_NEWUSER | 32 | #ifndef CLONE_NEWUSER |
@@ -124,6 +126,119 @@ static void chk_chroot(void) { | |||
124 | exit(1); | 126 | exit(1); |
125 | } | 127 | } |
126 | 128 | ||
129 | static void monitor_application(pid_t app_pid) { | ||
130 | while (app_pid) { | ||
131 | sleep(1); | ||
132 | |||
133 | int status; | ||
134 | unsigned rv = waitpid(app_pid, &status, 0); | ||
135 | if (arg_debug) | ||
136 | printf("Sandbox monitor: waitpid %u retval %d status %d\n", app_pid, rv, status); | ||
137 | |||
138 | DIR *dir; | ||
139 | if (!(dir = opendir("/proc"))) { | ||
140 | // sleep 2 seconds and try again | ||
141 | sleep(2); | ||
142 | if (!(dir = opendir("/proc"))) { | ||
143 | fprintf(stderr, "Error: cannot open /proc directory\n"); | ||
144 | exit(1); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | struct dirent *entry; | ||
149 | app_pid = 0; | ||
150 | while ((entry = readdir(dir)) != NULL) { | ||
151 | char *end; | ||
152 | unsigned pid; | ||
153 | if (sscanf(entry->d_name, "%u", &pid) != 1) | ||
154 | continue; | ||
155 | if (pid == 1) | ||
156 | continue; | ||
157 | app_pid = pid; | ||
158 | break; | ||
159 | } | ||
160 | closedir(dir); | ||
161 | |||
162 | if (app_pid != 0 && arg_debug) | ||
163 | printf("Sandbox monitor: monitoring %u\n", app_pid); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | |||
168 | static void start_application(void) { | ||
169 | //**************************************** | ||
170 | // start the program without using a shell | ||
171 | //**************************************** | ||
172 | if (arg_shell_none) { | ||
173 | if (arg_debug) { | ||
174 | int i; | ||
175 | for (i = cfg.original_program_index; i < cfg.original_argc; i++) { | ||
176 | if (cfg.original_argv[i] == NULL) | ||
177 | break; | ||
178 | printf("execvp argument %d: %s\n", i - cfg.original_program_index, cfg.original_argv[i]); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | if (!arg_command && !arg_quiet) | ||
183 | printf("Child process initialized\n"); | ||
184 | execvp(cfg.original_argv[cfg.original_program_index], &cfg.original_argv[cfg.original_program_index]); | ||
185 | } | ||
186 | //**************************************** | ||
187 | // start the program using a shell | ||
188 | //**************************************** | ||
189 | else { | ||
190 | // choose the shell requested by the user, or use bash as default | ||
191 | char *sh; | ||
192 | if (cfg.shell) | ||
193 | sh = cfg.shell; | ||
194 | else if (arg_zsh) | ||
195 | sh = "/usr/bin/zsh"; | ||
196 | else if (arg_csh) | ||
197 | sh = "/bin/csh"; | ||
198 | else | ||
199 | sh = "/bin/bash"; | ||
200 | |||
201 | char *arg[5]; | ||
202 | int index = 0; | ||
203 | arg[index++] = sh; | ||
204 | arg[index++] = "-c"; | ||
205 | assert(cfg.command_line); | ||
206 | if (arg_debug) | ||
207 | printf("Starting %s\n", cfg.command_line); | ||
208 | if (arg_doubledash) | ||
209 | arg[index++] = "--"; | ||
210 | arg[index++] = cfg.command_line; | ||
211 | arg[index] = NULL; | ||
212 | assert(index < 5); | ||
213 | |||
214 | if (arg_debug) { | ||
215 | char *msg; | ||
216 | if (asprintf(&msg, "sandbox %d, execvp into %s", sandbox_pid, cfg.command_line) == -1) | ||
217 | errExit("asprintf"); | ||
218 | logmsg(msg); | ||
219 | free(msg); | ||
220 | } | ||
221 | |||
222 | if (arg_debug) { | ||
223 | int i; | ||
224 | for (i = 0; i < 5; i++) { | ||
225 | if (arg[i] == NULL) | ||
226 | break; | ||
227 | printf("execvp argument %d: %s\n", i, arg[i]); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | if (!arg_command && !arg_quiet) | ||
232 | printf("Child process initialized\n"); | ||
233 | execvp(sh, arg); | ||
234 | } | ||
235 | |||
236 | perror("execvp"); | ||
237 | exit(1); // it should never get here!!! | ||
238 | } | ||
239 | |||
240 | |||
241 | |||
127 | int sandbox(void* sandbox_arg) { | 242 | int sandbox(void* sandbox_arg) { |
128 | // Get rid of unused parameter warning | 243 | // Get rid of unused parameter warning |
129 | (void)sandbox_arg; | 244 | (void)sandbox_arg; |
@@ -379,7 +494,7 @@ int sandbox(void* sandbox_arg) { | |||
379 | fs_delete_cp_command(); | 494 | fs_delete_cp_command(); |
380 | 495 | ||
381 | //**************************** | 496 | //**************************** |
382 | // start executable | 497 | // set application environment |
383 | //**************************** | 498 | //**************************** |
384 | prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // kill the child in case the parent died | 499 | prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // kill the child in case the parent died |
385 | int cwd = 0; | 500 | int cwd = 0; |
@@ -407,6 +522,9 @@ int sandbox(void* sandbox_arg) { | |||
407 | // set user-supplied environment variables | 522 | // set user-supplied environment variables |
408 | env_apply(); | 523 | env_apply(); |
409 | 524 | ||
525 | //**************************** | ||
526 | // set security filters | ||
527 | //**************************** | ||
410 | // set capabilities | 528 | // set capabilities |
411 | if (!arg_noroot) | 529 | if (!arg_noroot) |
412 | set_caps(); | 530 | set_caps(); |
@@ -477,73 +595,18 @@ int sandbox(void* sandbox_arg) { | |||
477 | 595 | ||
478 | 596 | ||
479 | //**************************************** | 597 | //**************************************** |
480 | // start the program without using a shell | 598 | // fork the application and monitor it |
481 | //**************************************** | ||
482 | if (arg_shell_none) { | ||
483 | if (arg_debug) { | ||
484 | int i; | ||
485 | for (i = cfg.original_program_index; i < cfg.original_argc; i++) { | ||
486 | if (cfg.original_argv[i] == NULL) | ||
487 | break; | ||
488 | printf("execvp argument %d: %s\n", i - cfg.original_program_index, cfg.original_argv[i]); | ||
489 | } | ||
490 | } | ||
491 | |||
492 | if (!arg_command && !arg_quiet) | ||
493 | printf("Child process initialized\n"); | ||
494 | execvp(cfg.original_argv[cfg.original_program_index], &cfg.original_argv[cfg.original_program_index]); | ||
495 | } | ||
496 | //**************************************** | ||
497 | // start the program using a shell | ||
498 | //**************************************** | 599 | //**************************************** |
499 | else { | 600 | pid_t app_pid = fork(); |
500 | // choose the shell requested by the user, or use bash as default | 601 | if (app_pid == -1) |
501 | char *sh; | 602 | errExit("fork"); |
502 | if (cfg.shell) | ||
503 | sh = cfg.shell; | ||
504 | else if (arg_zsh) | ||
505 | sh = "/usr/bin/zsh"; | ||
506 | else if (arg_csh) | ||
507 | sh = "/bin/csh"; | ||
508 | else | ||
509 | sh = "/bin/bash"; | ||
510 | |||
511 | char *arg[5]; | ||
512 | int index = 0; | ||
513 | arg[index++] = sh; | ||
514 | arg[index++] = "-c"; | ||
515 | assert(cfg.command_line); | ||
516 | if (arg_debug) | ||
517 | printf("Starting %s\n", cfg.command_line); | ||
518 | if (arg_doubledash) | ||
519 | arg[index++] = "--"; | ||
520 | arg[index++] = cfg.command_line; | ||
521 | arg[index] = NULL; | ||
522 | assert(index < 5); | ||
523 | |||
524 | if (arg_debug) { | ||
525 | char *msg; | ||
526 | if (asprintf(&msg, "sandbox %d, execvp into %s", sandbox_pid, cfg.command_line) == -1) | ||
527 | errExit("asprintf"); | ||
528 | logmsg(msg); | ||
529 | free(msg); | ||
530 | } | ||
531 | 603 | ||
532 | if (arg_debug) { | 604 | if (app_pid == 0) { |
533 | int i; | 605 | prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // kill the child in case the parent died |
534 | for (i = 0; i < 5; i++) { | 606 | start_application(); // start app |
535 | if (arg[i] == NULL) | ||
536 | break; | ||
537 | printf("execvp argument %d: %s\n", i, arg[i]); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | if (!arg_command && !arg_quiet) | ||
542 | printf("Child process initialized\n"); | ||
543 | execvp(sh, arg); | ||
544 | } | 607 | } |
545 | |||
546 | 608 | ||
547 | perror("execvp"); | 609 | monitor_application(app_pid); // monitor application |
610 | |||
548 | return 0; | 611 | return 0; |
549 | } | 612 | } |
diff --git a/test/fs_chroot.exp b/test/fs_chroot.exp index 4ddf8d32a..cc0d82179 100755 --- a/test/fs_chroot.exp +++ b/test/fs_chroot.exp | |||
@@ -54,7 +54,7 @@ sleep 1 | |||
54 | send -- "ps aux |wc -l; pwd\r" | 54 | send -- "ps aux |wc -l; pwd\r" |
55 | expect { | 55 | expect { |
56 | timeout {puts "TESTING ERROR 5\n";exit} | 56 | timeout {puts "TESTING ERROR 5\n";exit} |
57 | "5" | 57 | "6" |
58 | } | 58 | } |
59 | expect { | 59 | expect { |
60 | timeout {puts "TESTING ERROR 6\n";exit} | 60 | timeout {puts "TESTING ERROR 6\n";exit} |
diff --git a/test/ignore.exp b/test/ignore.exp index ab7f0655f..8f8076fb3 100755 --- a/test/ignore.exp +++ b/test/ignore.exp | |||
@@ -30,7 +30,7 @@ sleep 1 | |||
30 | send -- "ps aux | wc -l\r" | 30 | send -- "ps aux | wc -l\r" |
31 | expect { | 31 | expect { |
32 | timeout {puts "TESTING ERROR 4\n";exit} | 32 | timeout {puts "TESTING ERROR 4\n";exit} |
33 | "4" | 33 | "5" |
34 | } | 34 | } |
35 | sleep 1 | 35 | sleep 1 |
36 | send -- "exit\r" | 36 | send -- "exit\r" |
diff --git a/test/option-trace.exp b/test/option-trace.exp index b20ef9ef9..6fd113e2b 100755 --- a/test/option-trace.exp +++ b/test/option-trace.exp | |||
@@ -11,17 +11,17 @@ expect { | |||
11 | } | 11 | } |
12 | expect { | 12 | expect { |
13 | timeout {puts "TESTING ERROR 1\n";exit} | 13 | timeout {puts "TESTING ERROR 1\n";exit} |
14 | "1:bash:open /dev/tty" {puts "64bit\n"} | 14 | "bash:open /dev/tty" {puts "64bit\n"} |
15 | "1:bash:open64 /dev/tty" {puts "32bit\n"} | 15 | "bash:open64 /dev/tty" {puts "32bit\n"} |
16 | } | 16 | } |
17 | expect { | 17 | expect { |
18 | timeout {puts "TESTING ERROR 2\n";exit} | 18 | timeout {puts "TESTING ERROR 2\n";exit} |
19 | "1:bash:fopen /etc/passwd" | 19 | "bash:fopen /etc/passwd" |
20 | } | 20 | } |
21 | expect { | 21 | expect { |
22 | timeout {puts "TESTING ERROR 3\n";exit} | 22 | timeout {puts "TESTING ERROR 3\n";exit} |
23 | "1:bash:access /etc/terminfo/x/xterm" {puts "debian\n"} | 23 | "bash:access /etc/terminfo/x/xterm" {puts "debian\n"} |
24 | "1:bash:access /usr/share/terminfo/x/xterm" {puts "arch\n"} | 24 | "bash:access /usr/share/terminfo/x/xterm" {puts "arch\n"} |
25 | } | 25 | } |
26 | 26 | ||
27 | sleep 1 | 27 | sleep 1 |
diff --git a/test/pid.exp b/test/pid.exp index 0baf3af0e..d382feb96 100755 --- a/test/pid.exp +++ b/test/pid.exp | |||
@@ -37,7 +37,7 @@ sleep 1 | |||
37 | send -- "ps aux |wc -l; pwd\r" | 37 | send -- "ps aux |wc -l; pwd\r" |
38 | expect { | 38 | expect { |
39 | timeout {puts "TESTING ERROR 5\n";exit} | 39 | timeout {puts "TESTING ERROR 5\n";exit} |
40 | "5" | 40 | "6" |
41 | } | 41 | } |
42 | expect { | 42 | expect { |
43 | timeout {puts "TESTING ERROR 6\n";exit} | 43 | timeout {puts "TESTING ERROR 6\n";exit} |
diff --git a/test/trace.exp b/test/trace.exp index 2b5003d83..21dd6a559 100755 --- a/test/trace.exp +++ b/test/trace.exp | |||
@@ -11,7 +11,7 @@ expect { | |||
11 | } | 11 | } |
12 | expect { | 12 | expect { |
13 | timeout {puts "TESTING ERROR 1\n";exit} | 13 | timeout {puts "TESTING ERROR 1\n";exit} |
14 | "1:mkdir:mkdir ttt" | 14 | "mkdir:mkdir ttt" |
15 | } | 15 | } |
16 | sleep 1 | 16 | sleep 1 |
17 | 17 | ||
@@ -22,7 +22,7 @@ expect { | |||
22 | } | 22 | } |
23 | expect { | 23 | expect { |
24 | timeout {puts "TESTING ERROR 3\n";exit} | 24 | timeout {puts "TESTING ERROR 3\n";exit} |
25 | "1:rmdir:rmdir ttt" | 25 | "rmdir:rmdir ttt" |
26 | } | 26 | } |
27 | sleep 1 | 27 | sleep 1 |
28 | 28 | ||
@@ -33,8 +33,8 @@ expect { | |||
33 | } | 33 | } |
34 | expect { | 34 | expect { |
35 | timeout {puts "TESTING ERROR 5\n";exit} | 35 | timeout {puts "TESTING ERROR 5\n";exit} |
36 | "1:touch:open ttt" {puts "OK\n";} | 36 | "touch:open ttt" {puts "OK\n";} |
37 | "1:touch:open64 ttt" {puts "OK\n";} | 37 | "touch:open64 ttt" {puts "OK\n";} |
38 | } | 38 | } |
39 | sleep 1 | 39 | sleep 1 |
40 | 40 | ||
@@ -45,7 +45,7 @@ expect { | |||
45 | } | 45 | } |
46 | expect { | 46 | expect { |
47 | timeout {puts "TESTING ERROR 7\n";exit} | 47 | timeout {puts "TESTING ERROR 7\n";exit} |
48 | "1:rm:unlinkat ttt" | 48 | "rm:unlinkat ttt" |
49 | } | 49 | } |
50 | sleep 1 | 50 | sleep 1 |
51 | 51 | ||
@@ -56,26 +56,26 @@ expect { | |||
56 | } | 56 | } |
57 | expect { | 57 | expect { |
58 | timeout {puts "TESTING ERROR 8.2\n";exit} | 58 | timeout {puts "TESTING ERROR 8.2\n";exit} |
59 | "1:bash:open /dev/tty" {puts "OK\n";} | 59 | "bash:open /dev/tty" {puts "OK\n";} |
60 | "1:bash:open64 /dev/tty" {puts "OK\n";} | 60 | "bash:open64 /dev/tty" {puts "OK\n";} |
61 | } | 61 | } |
62 | expect { | 62 | expect { |
63 | timeout {puts "TESTING ERROR 8.3\n";exit} | 63 | timeout {puts "TESTING ERROR 8.3\n";exit} |
64 | "1:wget:fopen64 /etc/wgetrc" {puts "OK\n";} | 64 | "wget:fopen64 /etc/wgetrc" {puts "OK\n";} |
65 | "1:wget:fopen /etc/wgetrc" {puts "OK\n";} | 65 | "wget:fopen /etc/wgetrc" {puts "OK\n";} |
66 | } | 66 | } |
67 | expect { | 67 | expect { |
68 | timeout {puts "TESTING ERROR 8.4\n";exit} | 68 | timeout {puts "TESTING ERROR 8.4\n";exit} |
69 | "1:wget:fopen /etc/hosts" | 69 | "wget:fopen /etc/hosts" |
70 | } | 70 | } |
71 | expect { | 71 | expect { |
72 | timeout {puts "TESTING ERROR 8.5\n";exit} | 72 | timeout {puts "TESTING ERROR 8.5\n";exit} |
73 | "1:wget:connect" | 73 | "wget:connect" |
74 | } | 74 | } |
75 | expect { | 75 | expect { |
76 | timeout {puts "TESTING ERROR 8.6\n";exit} | 76 | timeout {puts "TESTING ERROR 8.6\n";exit} |
77 | "1:wget:fopen64 index.html" {puts "OK\n";} | 77 | "wget:fopen64 index.html" {puts "OK\n";} |
78 | "1:wget:fopen index.html" {puts "OK\n";} | 78 | "wget:fopen index.html" {puts "OK\n";} |
79 | } | 79 | } |
80 | sleep 1 | 80 | sleep 1 |
81 | 81 | ||
@@ -86,10 +86,9 @@ expect { | |||
86 | } | 86 | } |
87 | expect { | 87 | expect { |
88 | timeout {puts "TESTING ERROR 10\n";exit} | 88 | timeout {puts "TESTING ERROR 10\n";exit} |
89 | "1:rm:unlinkat index.html" | 89 | "rm:unlinkat index.html" |
90 | } | 90 | } |
91 | sleep 1 | 91 | sleep 1 |
92 | 92 | ||
93 | 93 | ||
94 | puts "\nall done\n" | 94 | puts "\nall done\n" |
95 | |||