diff options
author | smitsohu <smitsohu@gmail.com> | 2020-08-31 19:32:51 +0200 |
---|---|---|
committer | smitsohu <smitsohu@gmail.com> | 2020-08-31 19:32:51 +0200 |
commit | 4d43efd07b27929c9dcc308a76aaefb466bb1245 (patch) | |
tree | 2a22cf83753c87c0d305d98f221c7ced37309e36 | |
parent | chroot: unify path name handling (diff) | |
download | firejail-4d43efd07b27929c9dcc308a76aaefb466bb1245.tar.gz firejail-4d43efd07b27929c9dcc308a76aaefb466bb1245.tar.zst firejail-4d43efd07b27929c9dcc308a76aaefb466bb1245.zip |
join: move to mmapped sandbox status indicator
1) close #3612
2) remove an implicit limitation on rlimit-fsize option
(could not set limit to smaller than 6 bytes without affecting
the ability to join a sandbox)
3) rename 'join-or-start' file to just 'join'
4) when waiting for a sandbox that is not fully configured yet,
increase polling frequency from 10 per second to 100 per second
-rw-r--r-- | src/firejail/firejail.h | 3 | ||||
-rw-r--r-- | src/firejail/join.c | 59 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 51 | ||||
-rw-r--r-- | src/include/rundefs.h | 2 |
4 files changed, 39 insertions, 76 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 85139d75f..2bb8dd351 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -370,8 +370,9 @@ void check_user_namespace(void); | |||
370 | char *guess_shell(void); | 370 | char *guess_shell(void); |
371 | 371 | ||
372 | // sandbox.c | 372 | // sandbox.c |
373 | #define SANDBOX_DONE '1' | ||
373 | int sandbox(void* sandbox_arg); | 374 | int sandbox(void* sandbox_arg); |
374 | void start_application(int no_sandbox, FILE *fp) __attribute__((noreturn)); | 375 | void start_application(int no_sandbox, char *set_sandbox_status) __attribute__((noreturn)); |
375 | void set_apparmor(void); | 376 | void set_apparmor(void); |
376 | 377 | ||
377 | // network_main.c | 378 | // network_main.c |
diff --git a/src/firejail/join.c b/src/firejail/join.c index 14eea4612..c7619ef3b 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c | |||
@@ -292,7 +292,7 @@ static void extract_umask(pid_t pid) { | |||
292 | fprintf(stderr, "Error: cannot open umask file\n"); | 292 | fprintf(stderr, "Error: cannot open umask file\n"); |
293 | exit(1); | 293 | exit(1); |
294 | } | 294 | } |
295 | if (fscanf(fp, "%3o", &orig_umask) < 1) { | 295 | if (fscanf(fp, "%o", &orig_umask) != 1) { |
296 | fprintf(stderr, "Error: cannot read umask\n"); | 296 | fprintf(stderr, "Error: cannot read umask\n"); |
297 | exit(1); | 297 | exit(1); |
298 | } | 298 | } |
@@ -303,66 +303,33 @@ static void extract_umask(pid_t pid) { | |||
303 | // it is no firejail sandbox at all, return true if the sandbox is complete | 303 | // it is no firejail sandbox at all, return true if the sandbox is complete |
304 | bool is_ready_for_join(const pid_t pid) { | 304 | bool is_ready_for_join(const pid_t pid) { |
305 | EUID_ASSERT(); | 305 | EUID_ASSERT(); |
306 | // check if a file "ready-for-join" exists | 306 | // check if a file /run/firejail/mnt/join exists |
307 | char *fname; | 307 | char *fname; |
308 | if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_READY_FOR_JOIN) == -1) | 308 | if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_JOIN_FILE) == -1) |
309 | errExit("asprintf"); | 309 | errExit("asprintf"); |
310 | EUID_ROOT(); | 310 | EUID_ROOT(); |
311 | FILE *fp = fopen(fname, "re"); | 311 | int fd = open(fname, O_RDONLY|O_CLOEXEC); |
312 | EUID_USER(); | 312 | EUID_USER(); |
313 | free(fname); | 313 | free(fname); |
314 | if (!fp) | ||
315 | return false; | ||
316 | // regular file owned by root | ||
317 | int fd = fileno(fp); | ||
318 | if (fd == -1) | 314 | if (fd == -1) |
319 | errExit("fileno"); | 315 | return false; |
320 | struct stat s; | 316 | struct stat s; |
321 | if (fstat(fd, &s) == -1) | 317 | if (fstat(fd, &s) == -1) |
322 | errExit("fstat"); | 318 | errExit("fstat"); |
323 | if (!S_ISREG(s.st_mode) || s.st_uid != 0) { | 319 | if (!S_ISREG(s.st_mode) || s.st_uid != 0) { |
324 | fclose(fp); | 320 | close(fd); |
325 | return false; | 321 | return false; |
326 | } | 322 | } |
327 | // check if it is non-empty | 323 | char status; |
328 | char buf[BUFLEN]; | 324 | if (read(fd, &status, 1) == 1 && status == SANDBOX_DONE) { |
329 | if (fgets(buf, BUFLEN, fp) == NULL) { | 325 | close(fd); |
330 | fclose(fp); | 326 | return true; |
331 | return false; | ||
332 | } | 327 | } |
333 | fclose(fp); | 328 | close(fd); |
334 | // confirm "ready" string was written | 329 | return false; |
335 | if (strcmp(buf, "ready\n") != 0) | ||
336 | return false; | ||
337 | |||
338 | // walk down the process tree a few nodes, there should be no firejail leaf | ||
339 | #define MAXNODES 5 | ||
340 | pid_t current = pid, next; | ||
341 | int i; | ||
342 | for (i = 0; i < MAXNODES; i++) { | ||
343 | if (find_child(current, &next) == 1) { | ||
344 | // found a leaf | ||
345 | EUID_ROOT(); | ||
346 | char *comm = pid_proc_comm(current); | ||
347 | EUID_USER(); | ||
348 | if (!comm) { | ||
349 | fprintf(stderr, "Error: cannot read /proc file\n"); | ||
350 | exit(1); | ||
351 | } | ||
352 | if (strcmp(comm, "firejail") == 0) { | ||
353 | free(comm); | ||
354 | return false; | ||
355 | } | ||
356 | free(comm); | ||
357 | break; | ||
358 | } | ||
359 | current = next; | ||
360 | } | ||
361 | |||
362 | return true; | ||
363 | } | 330 | } |
364 | 331 | ||
365 | #define SNOOZE 100000 // sleep interval in microseconds | 332 | #define SNOOZE 10000 // sleep interval in microseconds |
366 | void check_join_permission(pid_t pid) { | 333 | void check_join_permission(pid_t pid) { |
367 | // check if pid belongs to a fully set up firejail sandbox | 334 | // check if pid belongs to a fully set up firejail sandbox |
368 | unsigned long i; | 335 | unsigned long i; |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 0965b1017..ef09a790c 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #include "firejail.h" | 21 | #include "firejail.h" |
22 | #include "../include/seccomp.h" | 22 | #include "../include/seccomp.h" |
23 | #include <sys/mman.h> | ||
23 | #include <sys/mount.h> | 24 | #include <sys/mount.h> |
24 | #include <sys/wait.h> | 25 | #include <sys/wait.h> |
25 | #include <sys/stat.h> | 26 | #include <sys/stat.h> |
@@ -204,16 +205,17 @@ static void save_umask(void) { | |||
204 | } | 205 | } |
205 | } | 206 | } |
206 | 207 | ||
207 | static FILE *create_ready_for_join_file(void) { | 208 | static char *create_join_file(void) { |
208 | FILE *fp = fopen(RUN_READY_FOR_JOIN, "wxe"); | 209 | int fd = open(RUN_JOIN_FILE, O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); |
209 | if (fp) { | 210 | if (fd == -1) |
210 | ASSERT_PERMS_STREAM(fp, 0, 0, 0644); | 211 | errExit("open"); |
211 | return fp; | 212 | if (ftruncate(fd, 1) == -1) |
212 | } | 213 | errExit("ftruncate"); |
213 | else { | 214 | char *rv = mmap(NULL, 1, PROT_WRITE, MAP_SHARED, fd, 0); |
214 | fprintf(stderr, "Error: cannot create %s\n", RUN_READY_FOR_JOIN); | 215 | if (rv == MAP_FAILED) |
215 | exit(1); | 216 | errExit("mmap"); |
216 | } | 217 | close(fd); |
218 | return rv; | ||
217 | } | 219 | } |
218 | 220 | ||
219 | static void sandbox_if_up(Bridge *br) { | 221 | static void sandbox_if_up(Bridge *br) { |
@@ -472,7 +474,7 @@ static int ok_to_run(const char *program) { | |||
472 | return 0; | 474 | return 0; |
473 | } | 475 | } |
474 | 476 | ||
475 | void start_application(int no_sandbox, FILE *fp) { | 477 | void start_application(int no_sandbox, char *set_sandbox_status) { |
476 | // set environment | 478 | // set environment |
477 | if (no_sandbox == 0) { | 479 | if (no_sandbox == 0) { |
478 | env_defaults(); | 480 | env_defaults(); |
@@ -492,16 +494,14 @@ void start_application(int no_sandbox, FILE *fp) { | |||
492 | if (arg_audit) { | 494 | if (arg_audit) { |
493 | assert(arg_audit_prog); | 495 | assert(arg_audit_prog); |
494 | 496 | ||
495 | if (fp) { | ||
496 | fprintf(fp, "ready\n"); | ||
497 | fclose(fp); | ||
498 | } | ||
499 | #ifdef HAVE_GCOV | 497 | #ifdef HAVE_GCOV |
500 | __gcov_dump(); | 498 | __gcov_dump(); |
501 | #endif | 499 | #endif |
502 | #ifdef HAVE_SECCOMP | 500 | #ifdef HAVE_SECCOMP |
503 | seccomp_install_filters(); | 501 | seccomp_install_filters(); |
504 | #endif | 502 | #endif |
503 | if (set_sandbox_status) | ||
504 | *set_sandbox_status = SANDBOX_DONE; | ||
505 | execl(arg_audit_prog, arg_audit_prog, NULL); | 505 | execl(arg_audit_prog, arg_audit_prog, NULL); |
506 | 506 | ||
507 | perror("execl"); | 507 | perror("execl"); |
@@ -530,16 +530,14 @@ void start_application(int no_sandbox, FILE *fp) { | |||
530 | 530 | ||
531 | int rv = ok_to_run(cfg.original_argv[cfg.original_program_index]); | 531 | int rv = ok_to_run(cfg.original_argv[cfg.original_program_index]); |
532 | 532 | ||
533 | if (fp) { | ||
534 | fprintf(fp, "ready\n"); | ||
535 | fclose(fp); | ||
536 | } | ||
537 | #ifdef HAVE_GCOV | 533 | #ifdef HAVE_GCOV |
538 | __gcov_dump(); | 534 | __gcov_dump(); |
539 | #endif | 535 | #endif |
540 | #ifdef HAVE_SECCOMP | 536 | #ifdef HAVE_SECCOMP |
541 | seccomp_install_filters(); | 537 | seccomp_install_filters(); |
542 | #endif | 538 | #endif |
539 | if (set_sandbox_status) | ||
540 | *set_sandbox_status = SANDBOX_DONE; | ||
543 | if (rv) | 541 | if (rv) |
544 | execvp(cfg.original_argv[cfg.original_program_index], &cfg.original_argv[cfg.original_program_index]); | 542 | execvp(cfg.original_argv[cfg.original_program_index], &cfg.original_argv[cfg.original_program_index]); |
545 | else | 543 | else |
@@ -591,16 +589,14 @@ void start_application(int no_sandbox, FILE *fp) { | |||
591 | if (!arg_command && !arg_quiet) | 589 | if (!arg_command && !arg_quiet) |
592 | print_time(); | 590 | print_time(); |
593 | 591 | ||
594 | if (fp) { | ||
595 | fprintf(fp, "ready\n"); | ||
596 | fclose(fp); | ||
597 | } | ||
598 | #ifdef HAVE_GCOV | 592 | #ifdef HAVE_GCOV |
599 | __gcov_dump(); | 593 | __gcov_dump(); |
600 | #endif | 594 | #endif |
601 | #ifdef HAVE_SECCOMP | 595 | #ifdef HAVE_SECCOMP |
602 | seccomp_install_filters(); | 596 | seccomp_install_filters(); |
603 | #endif | 597 | #endif |
598 | if (set_sandbox_status) | ||
599 | *set_sandbox_status = SANDBOX_DONE; | ||
604 | execvp(arg[0], arg); | 600 | execvp(arg[0], arg); |
605 | } | 601 | } |
606 | 602 | ||
@@ -1162,11 +1158,10 @@ int sandbox(void* sandbox_arg) { | |||
1162 | set_caps(); | 1158 | set_caps(); |
1163 | 1159 | ||
1164 | //**************************************** | 1160 | //**************************************** |
1165 | // communicate progress of sandbox set up | 1161 | // relay status information to join option |
1166 | // to --join | ||
1167 | //**************************************** | 1162 | //**************************************** |
1168 | 1163 | ||
1169 | FILE *rj = create_ready_for_join_file(); | 1164 | char *set_sandbox_status = create_join_file(); |
1170 | 1165 | ||
1171 | //**************************************** | 1166 | //**************************************** |
1172 | // create a new user namespace | 1167 | // create a new user namespace |
@@ -1248,10 +1243,10 @@ int sandbox(void* sandbox_arg) { | |||
1248 | set_nice(cfg.nice); | 1243 | set_nice(cfg.nice); |
1249 | set_rlimits(); | 1244 | set_rlimits(); |
1250 | 1245 | ||
1251 | start_application(0, rj); | 1246 | start_application(0, set_sandbox_status); |
1252 | } | 1247 | } |
1253 | 1248 | ||
1254 | fclose(rj); | 1249 | munmap(set_sandbox_status, 1); |
1255 | 1250 | ||
1256 | int status = monitor_application(app_pid); // monitor application | 1251 | int status = monitor_application(app_pid); // monitor application |
1257 | flush_stdin(); | 1252 | flush_stdin(); |
diff --git a/src/include/rundefs.h b/src/include/rundefs.h index d56623907..4da2db748 100644 --- a/src/include/rundefs.h +++ b/src/include/rundefs.h | |||
@@ -113,7 +113,7 @@ | |||
113 | #define RUN_FSLOGGER_FILE RUN_MNT_DIR "/fslogger" | 113 | #define RUN_FSLOGGER_FILE RUN_MNT_DIR "/fslogger" |
114 | #define RUN_TRACE_FILE RUN_MNT_DIR "/trace" | 114 | #define RUN_TRACE_FILE RUN_MNT_DIR "/trace" |
115 | #define RUN_UMASK_FILE RUN_MNT_DIR "/umask" | 115 | #define RUN_UMASK_FILE RUN_MNT_DIR "/umask" |
116 | #define RUN_JOIN_FILE RUN_MNT_DIR "/join" | ||
116 | #define RUN_OVERLAY_ROOT RUN_MNT_DIR "/oroot" | 117 | #define RUN_OVERLAY_ROOT RUN_MNT_DIR "/oroot" |
117 | #define RUN_READY_FOR_JOIN RUN_MNT_DIR "/ready-for-join" | ||
118 | 118 | ||
119 | #endif | 119 | #endif |