Skip to content

Commit

Permalink
Support for "tmp" rules
Browse files Browse the repository at this point in the history
We introduce a new kind of a directory rule, which binds a freshly
created temporary directory, writeable by the sandbox user. By default,
we install such a rule for "/tmp".

I also cleaned up checking of correctness of directory rules.
  • Loading branch information
gollux committed Aug 27, 2018
1 parent 8b81338 commit 715add2
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 17 deletions.
7 changes: 6 additions & 1 deletion isolate.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,14 @@ no setuid binaries). This behavior can be modified using the 'options':
Instead of binding a directory, mount a device-less filesystem called 'in'.
For example, this can be 'proc' or 'sysfs'.

*tmp*::
Bind a freshly created temporary directory writeable for the sandbox user.
Accepts no 'out', implies *rw*.

Unless *--no-default-dirs* is specified, the default set of directory rules binds +/bin+,
+/dev+ (with devices allowed), +/lib+, +/lib64+ (if it exists), and +/usr+. It also binds
the working directory to +/box+ (read-write) and mounts the proc filesystem at +/proc+.
the working directory to +/box+ (read-write), mounts the proc filesystem at +/proc+, and
creates a temporary directory +/tmp+.

*-D, --no-default-dirs*::
Do not bind the default set of directories. Care has to be taken to specify
Expand Down
3 changes: 2 additions & 1 deletion isolate.c
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,7 @@ Options:\n\
\t\t\t\tmaybe\tSkip the rule if <out> does not exist\n\
\t\t\t\tnoexec\tDo not allow execution of binaries\n\
\t\t\t\trw\tAllow read-write access\n\
\t\t\t\ttmp\tCreate as a temporary directory (implies rw)\n\
-D, --no-default-dirs\tDo not add default directory rules\n\
-f, --fsize=<size>\tMax size (in KB) of files that can be created\n\
-E, --env=<var>\t\tInherit the environment variable <var> from the parent process\n\
Expand Down Expand Up @@ -991,7 +992,7 @@ main(int argc, char **argv)
break;
case 'd':
if (!set_dir_action(optarg))
usage("Invalid directory specified: %s\n", optarg);
usage("Invalid directory rule specified: %s\n", optarg);
break;
case 'D':
default_dirs = 0;
Expand Down
61 changes: 46 additions & 15 deletions rules.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,12 @@ enum dir_rule_flags {
DIR_FLAG_FS = 4,
DIR_FLAG_MAYBE = 8,
DIR_FLAG_DEV = 16,
DIR_FLAG_TMP = 32,
DIR_FLAG_DEFAULT = 1U << 15, // Used internally
DIR_FLAG_DISABLED = 1U << 16, // Used internally
};

static const char * const dir_flag_names[] = { "rw", "noexec", "fs", "maybe", "dev" };
static const char * const dir_flag_names[] = { "rw", "noexec", "fs", "maybe", "dev", "tmp" };

static struct dir_rule *first_dir_rule;
static struct dir_rule **last_dir_rule = &first_dir_rule;
Expand Down Expand Up @@ -213,18 +214,6 @@ add_dir_rule(char *in, char *out, unsigned int flags)
if (!in)
return 0;

// Check "out"
if (flags & DIR_FLAG_FS)
{
if (!out || out[0] == '/')
return 0;
}
else
{
if (out && out[0] != '/' && strncmp(out, "./", 2))
return 0;
}

// Override an existing rule
struct dir_rule *r;
for (r = first_dir_rule; r; r = r->next)
Expand Down Expand Up @@ -273,9 +262,41 @@ set_dir_action_ext(char *arg, unsigned int ext_flags)

char *eq = strchr(arg, '=');
if (eq)
*eq++ = 0;

if ((flags & DIR_FLAG_FS) && (flags & DIR_FLAG_TMP))
return 0;

if (flags & DIR_FLAG_FS)
{
if (!eq || strchr(eq, '/'))
return 0;
return add_dir_rule(arg, eq, flags);
}
else if (flags & DIR_FLAG_TMP)
{
*eq++ = 0;
return add_dir_rule(arg, (*eq ? eq : NULL), flags);
if (eq)
return 0;
/*
* Construct an outside temporary directory, which will be later
* chowned to box_uid. The hierarchy of these directories is intentionally
* flat, so that we avoid writing to a directory which might have already
* tampered with in a previous run of the sandbox.
*/
char out[1024];
snprintf(out, sizeof(out), "./tmp/%s", arg);
for (char *p = out + strlen("./tmp/"); *p; p++)
if (*p == '/')
*p = ':'; // This is safe, there were no colons in "out"
return add_dir_rule(arg, xstrdup(out), flags | DIR_FLAG_RW);
}
else if (eq)
{
if (!eq[0])
return add_dir_rule(arg, NULL, flags);
if (eq[0] != '/' && strncmp(eq, "./", 2))
return 0;
return add_dir_rule(arg, eq, flags);
}
else
{
Expand Down Expand Up @@ -306,6 +327,7 @@ init_dir_rules(void)
set_dir_action_default("lib");
set_dir_action_default("lib64:maybe");
set_dir_action_default("proc=proc:fs");
set_dir_action_default("tmp:tmp");
set_dir_action_default("usr");
}

Expand Down Expand Up @@ -373,6 +395,15 @@ apply_dir_rules(int with_defaults)
char root_in[1024];
snprintf(root_in, sizeof(root_in), "root/%s", in);

if (r->flags & DIR_FLAG_TMP)
{
make_dir(out);
if (chown(out, box_uid, box_gid) < 0)
die("Cannot chown %s: %m", out);
if (chmod(out, 0700) < 0)
die("Cannot chmod %s: %m", out);
}

unsigned long mount_flags = 0;
if (!(r->flags & DIR_FLAG_RW))
mount_flags |= MS_RDONLY;
Expand Down

0 comments on commit 715add2

Please sign in to comment.