/* * Simple wrapper that does chroot, seccomp, * and sets resource limits, before dropping privileges */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SECURE_WRAP_MAX_ID 16384LU #define check(command) if ((command) != 0) { perror(#command); return(1); } #define error_eperm 1 int enable_seccomp(void) { struct sock_fprog filter; struct sock_filter rules[] = { #include "filter.h" }; filter.len = sizeof(rules) / sizeof(*rules); filter.filter = rules; check(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) check(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &filter)); return(0); } int main(int argc, char **argv) { const char *directory, *program; char *program_environment[4]; char *id_string; unsigned long id; struct rlimit limit; unsigned int tmp_fd; program_environment[0] = "HOME=/"; program_environment[1] = "TMPDIR=/tmp"; program_environment[2] = "PATH=/"; program_environment[3] = NULL; if (argc < 4) { fprintf(stderr, "usage: secure-wrap [...]\n"); return(2); } id_string = argv[1]; id = strtoul(id_string, NULL, 0); argc--; argv++; if (id > SECURE_WRAP_MAX_ID) { fprintf(stderr, "error: id may not exceed %lu\n", SECURE_WRAP_MAX_ID); return(4); } directory = argv[1]; argc--; argv++; program = argv[1]; argc--; argv++; /* * chroot */ check(chdir(directory)); check(chroot(directory)); check(chdir("/")); /* * Renice to avoid being able to use a lot of CPU */ setpriority(PRIO_PROCESS, 0, 19); /* * Close all file descriptors */ limit.rlim_cur = 8192; limit.rlim_max = 8192; check(getrlimit(RLIMIT_NOFILE, &limit)); for (tmp_fd = 3; tmp_fd < limit.rlim_max; tmp_fd++) { if (tmp_fd > INT_MAX) { return(3); } close(tmp_fd); } /* * Set resource limits */ /** ** Disallow many kinds of resources entirely **/ limit.rlim_cur = 0; limit.rlim_max = 0; check(setrlimit(RLIMIT_CORE, &limit)); check(setrlimit(RLIMIT_LOCKS, &limit)); check(setrlimit(RLIMIT_MEMLOCK, &limit)); check(setrlimit(RLIMIT_MSGQUEUE, &limit)); check(setrlimit(RLIMIT_FSIZE, &limit)); /** ** Allow a reasonable number of file descriptors **/ limit.rlim_cur = 16; limit.rlim_max = 16; check(setrlimit(RLIMIT_NOFILE, &limit)); /** ** Allow a reasonable number of processes **/ limit.rlim_cur = 5; limit.rlim_max = 5; check(setrlimit(RLIMIT_NPROC, &limit)); /** ** Allow a reasonable amount of CPU time **/ limit.rlim_cur = 90; limit.rlim_max = 90; check(setrlimit(RLIMIT_CPU, &limit)); /** ** Allow a reasonable amount of RAM **/ limit.rlim_cur = 1024 * 1024 * 64LU; limit.rlim_max = 1024 * 1024 * 64LU; check(setrlimit(RLIMIT_DATA, &limit)); check(setrlimit(RLIMIT_RSS, &limit)); check(setrlimit(RLIMIT_STACK, &limit)); limit.rlim_cur = 1024 * 1024 * 1024LU; limit.rlim_max = 1024 * 1024 * 1024LU; check(setrlimit(RLIMIT_AS, &limit)); /* * Drop privileges */ check(setgid(0x74636cLU + id)); check(setuid(0x74636cLU + id)); /* * Install seccomp filter */ check(enable_seccomp()); /* * Execute program */ check(execve(program, argv, program_environment)); /* * Failed to execute program */ return(1); }