static int ksandbox_capsicum_init_control(void *arg, int fd1, int fd2) { int rc; struct rlimit rl_zero; cap_rights_t rights; cap_rights_init(&rights); cap_rights_init(&rights, CAP_EVENT, CAP_FCNTL, CAP_ACCEPT); if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) { XWARN("cap_rights_limit: STDIN_FILENO"); return(0); } cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT); if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) { XWARN("cap_rights_limit: STDERR_FILENO"); return(0); } cap_rights_init(&rights, CAP_EVENT, CAP_FCNTL, CAP_READ, CAP_WRITE); if (cap_rights_limit(fd1, &rights) < 0 && errno != ENOSYS) { XWARN("cap_rights_limit: internal socket"); return(0); } rl_zero.rlim_cur = rl_zero.rlim_max = 0; if (-1 == setrlimit(RLIMIT_FSIZE, &rl_zero)) { XWARNX("setrlimit: rlimit_fsize"); return(0); } else if (-1 == setrlimit(RLIMIT_NPROC, &rl_zero)) { XWARNX("setrlimit: rlimit_nproc"); return(0); } rc = cap_enter(); if (0 != rc && errno != ENOSYS) { XWARN("cap_enter"); rc = 0; } else rc = 1; return(rc); }
int ksandbox_seccomp_init_child(void *arg, enum sandtype type) { struct rlimit rl_zero; int nnp_failed = 0; /* Set rlimits for completeness if possible. */ rl_zero.rlim_cur = rl_zero.rlim_max = 0; if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1) XWARN("setrlimit(RLIMIT_FSIZE)"); #if 0 /* * Don't do like OpenSSH: we need to pass stuff back and forth * over pipes, and this will prevent that from happening. */ if (setrlimit(RLIMIT_NOFILE, &rl_zero) == -1) XWARN("setrlimit(RLIMIT_NOFILE)"); #endif if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1) XWARN("setrlimit(RLIMIT_NPROC)"); #ifdef SANDBOX_SECCOMP_DEBUG ssh_sandbox_child_debugging(); #endif if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) { XWARN("prctl(PR_SET_NO_NEW_PRIVS)"); nnp_failed = 1; } if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, SAND_WORKER != type ? &preauth_prog_ctrl : &preauth_prog_work) == -1) XWARN("prctl(PR_SET_SECCOMP)"); else if (nnp_failed) { XWARNX("SECCOMP_MODE_FILTER activated but " "PR_SET_NO_NEW_PRIVS failed"); _exit(EXIT_FAILURE); } return(1); }
int ksandbox_darwin_init_child(void *arg, enum sandtype type) { int rc; char *er; struct rlimit rl_zero; rc = SAND_WORKER == type ? sandbox_init(kSBXProfilePureComputation, SANDBOX_NAMED, &er) : sandbox_init(kSBXProfileNoWrite, SANDBOX_NAMED, &er); if (0 != rc) { XWARNX("sandbox_init: %s", er); sandbox_free_error(er); rc = 0; } else rc = 1; rl_zero.rlim_cur = rl_zero.rlim_max = 0; #if 0 /* * FIXME: I've taken out the RLIMIT_NOFILE setrlimit() because * it causes strange behaviour. On Mac OS X, it fails with * EPERM no matter what (the same code runs fine when not run as * a CGI instance). */ if (-1 == setrlimit(RLIMIT_NOFILE, &rl_zero)) XWARN("setrlimit: rlimit_fsize"); #endif if (-1 == setrlimit(RLIMIT_FSIZE, &rl_zero)) XWARN("setrlimit: rlimit_fsize"); if (-1 == setrlimit(RLIMIT_NPROC, &rl_zero)) XWARN("setrlimit: rlimit_nproc"); return(rc); }
int ksandbox_pledge_init_child(void *arg, enum sandtype type) { const char *fl; fl = "stdio"; if (SAND_CONTROL == type) fl = "stdio unix sendfd recvfd"; if (-1 == pledge(fl, NULL)) { XWARN("pledge: %s", SAND_CONTROL == type ? "control" : "worker"); return(0); } return(1); }
int ksandbox_systrace_init_child(void *arg, enum sandtype type) { struct systrace_sandbox *box = arg; if (NULL == arg) { XWARNX("systrace child passed null config"); return(0); } signal(SIGCHLD, box->osigchld); if (kill(getpid(), SIGSTOP) == 0) return(1); XWARN("kill: SIGSTOP"); return(0); }
static int ksandbox_capsicum_init_control(void *arg, int worker, int fdfiled, int fdaccept) { int rc; struct rlimit rl_zero; cap_rights_t rights; cap_rights_init(&rights); if (-1 != fdaccept) { /* * If we have old-style accept FastCGI sockets, then * mark us as accepting on it. */ cap_rights_init(&rights, CAP_EVENT, CAP_FCNTL, CAP_ACCEPT); if (cap_rights_limit(fdaccept, &rights) < 0 && errno != ENOSYS) { XWARN("cap_rights_limit: accept socket"); return(0); } } else { /* New-style descriptor-passing socket. */ assert(-1 != fdfiled); cap_rights_init(&rights, CAP_EVENT, CAP_FCNTL, CAP_READ, CAP_WRITE); if (cap_rights_limit(fdfiled, &rights) < 0 && errno != ENOSYS) { XWARN("cap_rights_limit: descriptor socket"); return(0); } } /* Always pass through write-only stderr. */ cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT); if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) { XWARN("cap_rights_limit: STDERR_FILENO"); return(0); } /* Interface to worker. */ cap_rights_init(&rights, CAP_EVENT, CAP_FCNTL, CAP_READ, CAP_WRITE); if (cap_rights_limit(worker, &rights) < 0 && errno != ENOSYS) { XWARN("cap_rights_limit: internal socket"); return(0); } rl_zero.rlim_cur = rl_zero.rlim_max = 0; if (-1 == setrlimit(RLIMIT_FSIZE, &rl_zero)) { XWARNX("setrlimit: rlimit_fsize"); return(0); } else if (-1 == setrlimit(RLIMIT_NPROC, &rl_zero)) { XWARNX("setrlimit: rlimit_nproc"); return(0); } rc = cap_enter(); if (0 != rc && errno != ENOSYS) { XWARN("cap_enter"); rc = 0; } else rc = 1; return(rc); }
static int ksandbox_capsicum_init_worker(void *arg, int fd1, int fd2) { int rc; struct rlimit rl_zero; cap_rights_t rights; cap_rights_init(&rights); /* * Test for EBADF because STDIN_FILENO is usually closed by the * caller. */ cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_FSTAT); if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS && errno != EBADF) { XWARN("cap_rights_limit: STDIN_FILENO"); return(0); } cap_rights_init(&rights, CAP_EVENT, CAP_WRITE, CAP_FSTAT); if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) { XWARN("cap_rights_limit: STDERR_FILENO"); return(0); } cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE, CAP_FSTAT); if (-1 != fd1 && cap_rights_limit(fd1, &rights) < 0 && errno != ENOSYS) { XWARN("cap_rights_limit: internal socket"); return(0); } if (-1 != fd2 && cap_rights_limit(fd2, &rights) < 0 && errno != ENOSYS) { XWARN("cap_rights_limit: internal socket"); return(0); } rl_zero.rlim_cur = rl_zero.rlim_max = 0; if (-1 == setrlimit(RLIMIT_NOFILE, &rl_zero)) { XWARNX("setrlimit: rlimit_fsize"); return(0); } else if (-1 == setrlimit(RLIMIT_FSIZE, &rl_zero)) { XWARNX("setrlimit: rlimit_fsize"); return(0); } else if (-1 == setrlimit(RLIMIT_NPROC, &rl_zero)) { XWARNX("setrlimit: rlimit_nproc"); return(0); } rc = cap_enter(); if (0 != rc && errno != ENOSYS) { XWARN("cap_enter"); rc = 0; } else rc = 1; return(rc); }
int ksandbox_systrace_init_parent(void *arg, enum sandtype type, pid_t child) { struct systrace_sandbox *box = arg; int dev, i, j, found, st, rc; pid_t pid; struct systrace_policy policy; const struct systrace_preauth *preauth; assert(NULL != arg); preauth = SAND_WORKER != type ? preauth_control : preauth_worker; rc = 0; /* * Wait for the child to send itself a SIGSTOP. * When we receive it, the child is waiting to be sandboxed. */ do pid = waitpid(child, &st, WUNTRACED); while (pid == -1 && errno == EINTR); if (-1 == pid) { XWARN("waitpid"); return(0); } /* Catch if it exits. */ signal(SIGCHLD, box->osigchld); if ( ! WIFSTOPPED(st)) { if (WIFSIGNALED(st)) { XWARNX("child signal %d", WTERMSIG(st)); return(0); } else if (WIFEXITED(st)) { XWARNX("child exit %d", WEXITSTATUS(st)); return(0); } XWARNX("child not stopped"); return(0); } box->child_pid = child; /* Set up systracing of child */ if ((dev = open("/dev/systrace", O_RDONLY)) == -1) { if (ENXIO == errno) { XWARN("open: /dev/systrace (mounted nodev?)"); goto out; } XWARN("open: /dev/systrace"); goto out; } if (ioctl(dev, STRIOCCLONE, &box->systrace_fd) == -1) { XWARN("ioctl: STRIOCCLONE"); close(dev); goto out; } close(dev); if (ioctl(box->systrace_fd, STRIOCATTACH, &child) == -1) { XWARN("ioctl: STRIOCATTACH"); goto out; } /* Allocate and assign policy */ memset(&policy, 0, sizeof(policy)); policy.strp_op = SYSTR_POLICY_NEW; policy.strp_maxents = SYS_MAXSYSCALL; if (ioctl(box->systrace_fd, STRIOCPOLICY, &policy) == -1) { XWARN("ioctl: STRIOCPOLICY (new)"); goto out; } policy.strp_op = SYSTR_POLICY_ASSIGN; policy.strp_pid = box->child_pid; if (ioctl(box->systrace_fd, STRIOCPOLICY, &policy) == -1) { XWARN("ioctl: STRIOCPOLICY (assign)"); goto out; } /* Set per-syscall policy */ for (i = 0; i < SYS_MAXSYSCALL; i++) { found = 0; for (j = 0; preauth[j].syscall != -1; j++) { if (preauth[j].syscall == i) { found = 1; break; } } policy.strp_op = SYSTR_POLICY_MODIFY; policy.strp_code = i; policy.strp_policy = found ? preauth[j].action : SYSTR_POLICY_KILL; if (ioctl(box->systrace_fd, STRIOCPOLICY, &policy) == -1) { XWARN("ioctl: STRIOCPOLICY (modify)"); goto out; } } rc = 1; out: /* Signal the child to start running */ if (kill(box->child_pid, SIGCONT) == 0) return(rc); XWARN("kill: SIGCONT"); return(0); }