/*
* Simple wrapper that does chroot, seccomp,
* and sets resource limits, before dropping privileges
*/
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <sys/resource.h>
#include <linux/audit.h>
#include <sys/socket.h>
#include <sys/ptrace.h>
#include <sys/prctl.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <limits.h>
#include <errno.h>
#include <stdio.h>
#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 <id> <directory> <program> [<args>...]\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);
}