void caps_print_filter(pid_t pid) { EUID_ASSERT(); // in case the pid is that of a firejail process, use the pid of the first child process pid = switch_to_child(pid); // now check if the pid belongs to a firejail sandbox if (invalid_sandbox(pid)) { fprintf(stderr, "Error: no valid sandbox\n"); exit(1); } // check privileges for non-root users uid_t uid = getuid(); if (uid != 0) { uid_t sandbox_uid = pid_get_uid(pid); if (uid != sandbox_uid) { fprintf(stderr, "Error: permission denied.\n"); exit(1); } } uint64_t caps = extract_caps(pid); int i; uint64_t mask; int elems = sizeof(capslist) / sizeof(capslist[0]); for (i = 0, mask = 1; i < elems; i++, mask <<= 1) { printf("%-18.18s - %s\n", capslist[i].name, (mask & caps)? "enabled": "disabled"); } exit(0); }
void fs_logger_print_log(pid_t pid) { EUID_ASSERT(); // in case the pid is that of a firejail process, use the pid of the first child process pid = switch_to_child(pid); // check privileges for non-root users uid_t uid = getuid(); if (uid != 0) { uid_t sandbox_uid = pid_get_uid(pid); if (uid != sandbox_uid) { fprintf(stderr, "Error: permission denied\n"); exit(1); } } // print RUN_FSLOGGER_FILE char *fname; if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_FSLOGGER_FILE) == -1) errExit("asprintf"); EUID_ROOT(); struct stat s; if (stat(fname, &s) == -1 || s.st_uid != 0) { fprintf(stderr, "Error: Cannot access filesystem log\n"); exit(1); } /* coverity[toctou] */ FILE *fp = fopen(fname, "r"); if (!fp) { fprintf(stderr, "Error: Cannot open filesystem log\n"); exit(1); } char buf[MAXBUF]; while (fgets(buf, MAXBUF, fp)) printf("%s", buf); fclose(fp); free(fname); exit(0); }
void join(pid_t pid, int argc, char **argv, int index) { EUID_ASSERT(); pid_t parent = pid; // in case the pid is that of a firejail process, use the pid of the first child process pid = switch_to_child(pid); // now check if the pid belongs to a firejail sandbox if (invalid_sandbox(pid)) { fprintf(stderr, "Error: no valid sandbox\n"); exit(1); } // check privileges for non-root users uid_t uid = getuid(); if (uid != 0) { uid_t sandbox_uid = pid_get_uid(pid); if (uid != sandbox_uid) { fprintf(stderr, "Error: permission is denied to join a sandbox created by a different user.\n"); exit(1); } } extract_x11_display(parent); EUID_ROOT(); // in user mode set caps seccomp, cpu, cgroup, etc if (getuid() != 0) { extract_nonewprivs(pid); // redundant on Linux >= 4.10; duplicated in function extract_caps extract_caps(pid); extract_cpu(pid); extract_cgroup(pid); extract_nogroups(pid); extract_user_namespace(pid); } // set cgroup if (cfg.cgroup) // not available for uid 0 set_cgroup(cfg.cgroup); // set umask, also uid 0 extract_umask(pid); // join namespaces if (arg_join_network) { if (join_namespace(pid, "net")) exit(1); } else if (arg_join_filesystem) { if (join_namespace(pid, "mnt")) exit(1); } else { if (join_namespace(pid, "ipc") || join_namespace(pid, "net") || join_namespace(pid, "pid") || join_namespace(pid, "uts") || join_namespace(pid, "mnt")) exit(1); } pid_t child = fork(); if (child < 0) errExit("fork"); if (child == 0) { // drop discretionary access control capabilities for root sandboxes caps_drop_dac_override(); // chroot into /proc/PID/root directory char *rootdir; if (asprintf(&rootdir, "/proc/%d/root", pid) == -1) errExit("asprintf"); int rv; if (!arg_join_network) { rv = chroot(rootdir); // this will fail for processes in sandboxes not started with --chroot option if (rv == 0) printf("changing root to %s\n", rootdir); } EUID_USER(); if (chdir("/") < 0) errExit("chdir"); if (cfg.homedir) { struct stat s; if (stat(cfg.homedir, &s) == 0) { /* coverity[toctou] */ if (chdir(cfg.homedir) < 0) errExit("chdir"); } } // set caps filter EUID_ROOT(); if (apply_caps == 1) // not available for uid 0 caps_set(caps); #ifdef HAVE_SECCOMP if (getuid() != 0) seccomp_load_file_list(); #endif // mount user namespace or drop privileges if (arg_noroot) { // not available for uid 0 if (arg_debug) printf("Joining user namespace\n"); if (join_namespace(1, "user")) exit(1); // user namespace resets capabilities // set caps filter if (apply_caps == 1) // not available for uid 0 caps_set(caps); } // set nonewprivs if (arg_nonewprivs == 1) { // not available for uid 0 int rv = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); if (arg_debug && rv == 0) printf("NO_NEW_PRIVS set\n"); } EUID_USER(); int cwd = 0; if (cfg.cwd) { if (chdir(cfg.cwd) == 0) cwd = 1; } if (!cwd) { if (chdir("/") < 0) errExit("chdir"); if (cfg.homedir) { struct stat s; if (stat(cfg.homedir, &s) == 0) { /* coverity[toctou] */ if (chdir(cfg.homedir) < 0) errExit("chdir"); } } } // drop privileges drop_privs(arg_nogroups); // kill the child in case the parent died prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); extract_command(argc, argv, index); if (cfg.command_line == NULL) { assert(cfg.shell); cfg.command_line = cfg.shell; cfg.window_title = cfg.shell; } if (arg_debug) printf("Extracted command #%s#\n", cfg.command_line); // set cpu affinity if (cfg.cpus) // not available for uid 0 set_cpu_affinity(); // set nice value if (arg_nice) set_nice(cfg.nice); // add x11 display if (display) { char *display_str; if (asprintf(&display_str, ":%d", display) == -1) errExit("asprintf"); setenv("DISPLAY", display_str, 1); free(display_str); } start_application(0, NULL); // it will never get here!!! } int status = 0; //***************************** // following code is signal-safe install_handler(); // wait for the child to finish waitpid(child, &status, 0); // restore default signal action signal(SIGTERM, SIG_DFL); // end of signal-safe code //***************************** flush_stdin(); if (WIFEXITED(status)) { status = WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { status = WTERMSIG(status); } else { status = 0; } exit(status); }