X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=src%2Fbox.c;h=585eba09fdaf2abfe2a5bf68b95afe6514050bff;hb=6cba59728737842b32077102280642d269b78d90;hp=6c120f821f36436ddd478eb5f16fb6ac9d4be094;hpb=62f031249f096887b62544f8e4513fd225ac86fd;p=moe.git diff --git a/src/box.c b/src/box.c index 6c120f8..585eba0 100644 --- a/src/box.c +++ b/src/box.c @@ -45,6 +45,7 @@ static volatile int timer_tick; static struct timeval start_time; static int ticks_per_sec; static int exec_seen; +static int partial_line; #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0 /* glibc 2.1 or newer -> has lseek64 */ @@ -68,11 +69,20 @@ box_exit(void) exit(1); } +static void +flush_line(void) +{ + if (partial_line) + fputc('\n', stderr); + partial_line = 0; +} + static void NONRET __attribute__((format(printf,1,2))) die(char *msg, ...) { va_list args; va_start(args, msg); + flush_line(); vfprintf(stderr, msg, args); fputc('\n', stderr); box_exit(); @@ -85,6 +95,9 @@ msg(char *msg, ...) va_start(args, msg); if (verbose) { + int len = strlen(msg); + if (len > 0) + partial_line = (msg[len-1] != '\n'); vfprintf(stderr, msg, args); fflush(stderr); } @@ -100,6 +113,8 @@ xmalloc(size_t size) return p; } +/*** Syscall rules ***/ + static const char * const syscall_names[] = { #include "syscall-table.h" }; @@ -108,7 +123,7 @@ static const char * const syscall_names[] = { enum action { A_DEFAULT, // Use the default action - A_NO, // Always forbid + A_NO, // Always forbid A_YES, // Always permit A_FILENAME, // Permit if arg1 is a known filename A_LIBERAL = 128, // Valid only in liberal mode @@ -274,6 +289,8 @@ set_syscall_action(char *a) return 1; } +/*** Path rules ***/ + struct path_rule { char *path; enum action action; @@ -313,7 +330,7 @@ set_path_action(char *a) return 0; } - struct path_rule *r = xmalloc(sizeof(*r) + strlen(a)); + struct path_rule *r = xmalloc(sizeof(*r) + strlen(a) + 1); r->path = (char *)(r+1); strcpy(r->path, a); r->action = act; @@ -339,6 +356,143 @@ match_path_rule(struct path_rule *r, char *path) return r->action; } +/*** Environment rules ***/ + +struct env_rule { + char *var; // Variable to match + char *val; // ""=clear, NULL=inherit + int var_len; + struct env_rule *next; +}; + +static struct env_rule *first_env_rule; +static struct env_rule **last_env_rule = &first_env_rule; + +static struct env_rule default_env_rules[] = { + { "LIBC_FATAL_STDERR_", "1" } +}; + +static int +set_env_action(char *a0) +{ + struct env_rule *r = xmalloc(sizeof(*r) + strlen(a0) + 1); + char *a = (char *)(r+1); + strcpy(a, a0); + + char *sep = strchr(a, '='); + if (sep == a) + return 0; + r->var = a; + if (sep) + { + *sep++ = 0; + r->val = sep; + } + else + r->val = NULL; + *last_env_rule = r; + last_env_rule = &r->next; + r->next = NULL; + return 1; +} + +static int +match_env_var(char *env_entry, struct env_rule *r) +{ + if (strncmp(env_entry, r->var, r->var_len)) + return 0; + return (env_entry[r->var_len] == '='); +} + +static void +apply_env_rule(char **env, int *env_sizep, struct env_rule *r) +{ + // First remove the variable if already set + int pos = 0; + while (pos < *env_sizep && !match_env_var(env[pos], r)) + pos++; + if (pos < *env_sizep) + { + (*env_sizep)--; + env[pos] = env[*env_sizep]; + env[*env_sizep] = NULL; + } + + // What is the new value? + char *new; + if (r->val) + { + if (!r->val[0]) + return; + new = xmalloc(r->var_len + 1 + strlen(r->val) + 1); + sprintf(new, "%s=%s", r->var, r->val); + } + else + { + pos = 0; + while (environ[pos] && !match_env_var(environ[pos], r)) + pos++; + if (!(new = environ[pos])) + return; + } + + // Add it at the end of the array + env[(*env_sizep)++] = new; + env[*env_sizep] = NULL; +} + +static char ** +setup_environment(void) +{ + // Link built-in rules with user rules + for (int i=ARRAY_SIZE(default_env_rules)-1; i >= 0; i--) + { + default_env_rules[i].next = first_env_rule; + first_env_rule = &default_env_rules[i]; + } + + // Scan the original environment + char **orig_env = environ; + int orig_size = 0; + while (orig_env[orig_size]) + orig_size++; + + // For each rule, reserve one more slot and calculate length + int num_rules = 0; + for (struct env_rule *r = first_env_rule; r; r=r->next) + { + num_rules++; + r->var_len = strlen(r->var); + } + + // Create a new environment + char **env = xmalloc((orig_size + num_rules + 1) * sizeof(char *)); + int size; + if (pass_environ) + { + memcpy(env, environ, orig_size * sizeof(char *)); + size = orig_size; + } + else + size = 0; + env[size] = NULL; + + // Apply the rules one by one + for (struct env_rule *r = first_env_rule; r; r=r->next) + apply_env_rule(env, &size, r); + + // Return the new env and pass some gossip + if (verbose > 1) + { + fprintf(stderr, "Passing environment:\n"); + for (int i=0; env[i]; i++) + fprintf(stderr, "\t%s\n", env[i]); + } + return env; +} + +/*** Syscall checks ***/ + static void valid_filename(unsigned long addr) { @@ -571,6 +725,7 @@ boxkeeper(void) die("Time limit exceeded"); if (wall_timeout && wall_ms > wall_timeout) die("Time limit exceeded (wall clock)"); + flush_line(); fprintf(stderr, "OK (%d.%03d sec real, %d.%03d sec wall, %d syscalls)\n", (int) total.tv_sec, (int) total.tv_usec/1000, (int) wall.tv_sec, (int) wall.tv_usec/1000, @@ -642,7 +797,6 @@ box_inside(int argc, char **argv) { struct rlimit rl; char *args[argc+1]; - char *env[] = { "LIBC_FATAL_STDERR_=1", NULL }; memcpy(args, argv, argc * sizeof(char *)); args[argc] = NULL; @@ -679,7 +833,7 @@ box_inside(int argc, char **argv) signal(SIGCHLD, SIG_IGN); raise(SIGCHLD); } - execve(args[0], args, (pass_environ ? environ : env)); + execve(args[0], args, setup_environment()); die("execve(\"%s\"): %m", args[0]); } @@ -693,7 +847,9 @@ Usage: box [] -- \n\ Options:\n\ -a \tSet file access level (0=none, 1=cwd, 2=/etc,/lib,..., 3=whole fs, 9=no checks; needs -f)\n\ -c \tChange directory to first\n\ --e\t\tPass full environment of parent process\n\ +-e\t\tInherit full environment of the parent process\n\ +-E \tInherit the environment variable from the parent process\n\ +-E =\tSet the environment variable to ; unset it if is empty\n\ -f\t\tFilter system calls (-ff=very restricted)\n\ -i \tRedirect stdin from \n\ -m \tLimit address space to KB\n\ @@ -704,7 +860,7 @@ Options:\n\ -s =\tDefine action for the specified syscall (=yes/no/file)\n\ -t