diff options
Diffstat (limited to 'src/firejail/sandbox.c')
-rw-r--r-- | src/firejail/sandbox.c | 193 |
1 files changed, 128 insertions, 65 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 | } |