/*
* A Process Isolator based on Linux Containers
*
- * (c) 2012-2013 Martin Mares <mj@ucw.cz>
- * (c) 2012-2013 Bernard Blackham <bernard@blackham.com.au>
+ * (c) 2012-2015 Martin Mares <mj@ucw.cz>
+ * (c) 2012-2014 Bernard Blackham <bernard@blackham.com.au>
*/
+/***********************************************************
+ ** This is not the master version of Isolate any longer. **
+ ** See https://github.com/ioi/isolate for its new home. **
+ ***********************************************************/
+
#define _GNU_SOURCE
#include "autoconf.h"
#include <getopt.h>
#include <sched.h>
#include <time.h>
+#include <ftw.h>
#include <grp.h>
#include <mntent.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/quota.h>
#include <sys/vfs.h>
+#include <sys/fsuid.h>
#define NONRET __attribute__((noreturn))
#define UNUSED __attribute__((unused))
static gid_t orig_gid;
static int partial_line;
-static char cleanup_cmd[256];
+static int cleanup_ownership;
static struct timeval start_time;
static int ticks_per_sec;
static int get_wall_time_ms(void);
static int get_run_time_ms(struct rusage *rus);
+static void chowntree(char *path, uid_t uid, gid_t gid);
+
/*** Meta-files ***/
static FILE *metafile;
metafile = stdout;
return;
}
+ if (setfsuid(getuid()) < 0)
+ die("Failed to switch FS UID: %m");
metafile = fopen(name, "w");
+ if (setfsuid(geteuid()) < 0)
+ die("Failed to switch FS UID back: %m");
if (!metafile)
die("Failed to open metafile '%s'",name);
}
/*** Messages and exits ***/
-static void
-xsystem(const char *cmd)
-{
- int ret = system(cmd);
- if (ret < 0)
- die("system(\"%s\"): %m", cmd);
- if (!WIFEXITED(ret) || WEXITSTATUS(ret))
- die("system(\"%s\"): Exited with status %d", cmd, ret);
-}
-
static void NONRET
box_exit(int rc)
{
final_stats(&rus);
}
- if (rc < 2 && cleanup_cmd[0])
- xsystem(cleanup_cmd);
+ if (rc < 2 && cleanup_ownership)
+ chowntree("box", orig_uid, orig_gid);
meta_close();
exit(rc);
return (stat(path, &st) >= 0 && S_ISDIR(st.st_mode));
}
+static int rmtree_helper(const char *fpath, const struct stat *sb,
+ int typeflag UNUSED, struct FTW *ftwbuf UNUSED)
+{
+ if (S_ISDIR(sb->st_mode))
+ {
+ if (rmdir(fpath) < 0)
+ die("Cannot rmdir %s: %m", fpath);
+ }
+ else
+ {
+ if (unlink(fpath) < 0)
+ die("Cannot unlink %s: %m", fpath);
+ }
+ return FTW_CONTINUE;
+}
+
+static void
+rmtree(char *path)
+{
+ nftw(path, rmtree_helper, 32, FTW_MOUNT | FTW_PHYS | FTW_DEPTH);
+}
+
+static uid_t chown_uid;
+static gid_t chown_gid;
+
+static int chowntree_helper(const char *fpath, const struct stat *sb UNUSED,
+ int typeflag UNUSED, struct FTW *ftwbuf UNUSED)
+{
+ if (lchown(fpath, chown_uid, chown_gid) < 0)
+ die("Cannot chown %s: %m", fpath);
+ else
+ return FTW_CONTINUE;
+}
+
+static void
+chowntree(char *path, uid_t uid, gid_t gid)
+{
+ chown_uid = uid;
+ chown_gid = gid;
+ nftw(path, chowntree_helper, 32, FTW_MOUNT | FTW_PHYS);
+}
+
/*** Environment rules ***/
struct env_rule {
#define FOREACH_CG_CONTROLLER(_controller) \
for (cg_controller (_controller) = 0; \
- (_controller) < CG_NUM_CONTROLLERS; (_controller)++)
+ (_controller) < CG_NUM_CONTROLLERS; (_controller)++)
static const char *cg_controller_name(cg_controller c)
{
return cg_controllers[c].name;
}
-static const int cg_controller_optional(cg_controller c)
+static int cg_controller_optional(cg_controller c)
{
return cg_controllers[c].optional;
}
int n = read(fd, buf, CG_BUFSIZE);
if (n < 0)
- die("Cannot read %s: %m", path);
+ {
+ if (maybe)
+ return 0;
+ die("Cannot read %s: %m", path);
+ }
if (n >= CG_BUFSIZE - 1)
die("Attribute %s too long", path);
if (n > 0 && buf[n-1] == '\n')
if (cg_memory_limit)
{
cg_write(CG_MEMORY, "memory.limit_in_bytes", "%lld\n", (long long) cg_memory_limit << 10);
- cg_write(CG_MEMORY, "memory.memsw.limit_in_bytes", "%lld\n", (long long) cg_memory_limit << 10);
+ cg_write(CG_MEMORY, "?memory.memsw.limit_in_bytes", "%lld\n", (long long) cg_memory_limit << 10);
}
if (cg_timing)
FOREACH_CG_CONTROLLER(controller)
{
- if (cg_controller_optional(controller)) {
- if (!cg_read(controller, "?tasks", buf))
- continue;
- } else
+ if (cg_controller_optional(controller))
+ {
+ if (!cg_read(controller, "?tasks", buf))
+ continue;
+ }
+ else
cg_read(controller, "tasks", buf);
if (buf[0])
#define RLIM(res, val) setup_rlim("RLIMIT_" #res, RLIMIT_##res, val)
if (memory_limit)
- RLIM(AS, memory_limit * 1024);
+ RLIM(AS, (rlim_t)memory_limit * 1024);
RLIM(STACK, (stack_limit ? (rlim_t)stack_limit * 1024 : RLIM_INFINITY));
RLIM(NOFILE, 64);
char **args = arg;
write_errors_to_fd = error_pipes[1];
close(error_pipes[0]);
+ meta_close();
cg_enter();
setup_root();
init(void)
{
msg("Preparing sandbox directory\n");
- xsystem("rm -rf box");
+ rmtree("box");
if (mkdir("box", 0700) < 0)
die("Cannot create box: %m");
if (chown("box", orig_uid, orig_gid) < 0)
die("Box directory not found, there isn't anything to clean up");
msg("Deleting sandbox directory\n");
- xsystem("rm -rf *");
- if (rmdir(box_dir) < 0)
- die("Cannot remove %s: %m", box_dir);
+ rmtree(box_dir);
cg_remove();
}
if (!dir_exists("box"))
die("Box directory not found, did you run `isolate --init'?");
- char cmd[256];
- snprintf(cmd, sizeof(cmd), "chown -R %d.%d box", box_uid, box_gid);
- xsystem(cmd);
- snprintf(cleanup_cmd, sizeof(cleanup_cmd), "chown -R %d.%d box", orig_uid, orig_gid);
+ chowntree("box", box_uid, box_gid);
+ cleanup_ownership = 1;
if (pipe(error_pipes) < 0)
die("pipe: %m");
case OPT_RUN:
case OPT_CLEANUP:
case OPT_VERSION:
- if (!mode || mode == c)
+ if (!mode || (int) mode == c)
mode = c;
else
usage("Only one command is allowed.\n");