#include <libubus.h>
#define STACK_SIZE (1024 * 1024)
-#define OPT_ARGS "S:C:n:h:r:w:d:psulocU:G:NR:fF"
+#define OPT_ARGS "S:C:n:h:r:w:d:psulocU:G:NR:fFO:T:"
static struct {
char *name;
char *user;
char *group;
char *extroot;
+ char *overlaydir;
+ char *tmpoverlaysize;
int no_new_privs;
int namespace;
int procfs;
return _mount_bind(root, path, NULL, readonly, 0, error);
}
+static int mount_overlay(char *jail_root, char *overlaydir) {
+ char *upperdir, *workdir, *optsstr;
+ const char mountoptsformat[] = "lowerdir=%s,upperdir=%s,workdir=%s";
+ int ret = -1;
+
+ if (asprintf(&upperdir, "%s%s", overlaydir, "/upper") < 0)
+ goto out;
+
+ if (asprintf(&workdir, "%s%s", overlaydir, "/work") < 0)
+ goto upper_printf;
+
+ if (asprintf(&optsstr, mountoptsformat, jail_root, upperdir, workdir) < 0)
+ goto work_printf;
+
+ if (mkdir_p(upperdir, 0755) || mkdir_p(workdir, 0755))
+ goto opts_printf;
+
+ DEBUG("mount -t overlay %s %s (%s)\n", jail_root, jail_root, optsstr);
+
+ if (mount(jail_root, jail_root, "overlay", MS_NOATIME, optsstr))
+ goto opts_printf;
+
+ ret = 0;
+
+opts_printf:
+ free(optsstr);
+work_printf:
+ free(workdir);
+upper_printf:
+ free(upperdir);
+out:
+ return ret;
+}
+
static int build_jail_fs(void)
{
char jail_root[] = "/tmp/ujail-XXXXXX";
+ char tmpovdir[] = "/tmp/ujail-overlay-XXXXXX";
+ char *overlaydir = NULL;
+
if (mkdtemp(jail_root) == NULL) {
ERROR("mkdtemp(%s) failed: %m\n", jail_root);
return -1;
}
}
+ if (opts.tmpoverlaysize) {
+ char mountoptsstr[] = "mode=0755,size=XXXXXXXX";
+
+ snprintf(mountoptsstr, sizeof(mountoptsstr),
+ "mode=0755,size=%s", opts.tmpoverlaysize);
+ if (mkdtemp(tmpovdir) == NULL) {
+ ERROR("mkdtemp(%s) failed: %m\n", jail_root);
+ return -1;
+ }
+ if (mount("tmpfs", tmpovdir, "tmpfs", MS_NOATIME,
+ mountoptsstr)) {
+ ERROR("failed to mount tmpfs for overlay (size=%s)\n", opts.tmpoverlaysize);
+ return -1;
+ }
+ overlaydir = tmpovdir;
+ }
+
+ if (opts.overlaydir)
+ overlaydir = opts.overlaydir;
+
+ if (overlaydir)
+ mount_overlay(jail_root, overlaydir);
+
if (chdir(jail_root)) {
ERROR("chdir(%s) (jail_root) failed: %m\n", jail_root);
return -1;
}
snprintf(dirbuf, sizeof(dirbuf), "/old%s", jail_root);
+ umount2(dirbuf, MNT_DETACH);
rmdir(dirbuf);
+ if (opts.tmpoverlaysize) {
+ char tmpdirbuf[sizeof(tmpovdir) + 4];
+ snprintf(tmpdirbuf, sizeof(tmpdirbuf), "/old%s", tmpovdir);
+ umount2(tmpdirbuf, MNT_DETACH);
+ rmdir(tmpdirbuf);
+ }
+
umount2("/old", MNT_DETACH);
rmdir("/old");
fprintf(stderr, "namespace jail options:\n");
fprintf(stderr, " -h <hostname>\tchange the hostname of the jail\n");
fprintf(stderr, " -N\t\tjail has network namespace\n");
+ fprintf(stderr, " -f\t\tjail has user namespace\n");
+ fprintf(stderr, " -F\t\tjail has cgroups namespace\n");
fprintf(stderr, " -r <file>\treadonly files that should be staged\n");
fprintf(stderr, " -w <file>\twriteable files that should be staged\n");
fprintf(stderr, " -p\t\tjail has /proc\n");
fprintf(stderr, " -G <name>\tgroup to run jailed process\n");
fprintf(stderr, " -o\t\tremont jail root (/) read only\n");
fprintf(stderr, " -R <dir>\texternal jail rootfs (system container)\n");
+ fprintf(stderr, " -O <dir>\tdirectory for r/w overlayfs\n");
+ fprintf(stderr, " -T <size>\tuse tmpfs r/w overlayfs with <size>\n");
fprintf(stderr, "\nWarning: by default root inside the jail is the same\n\
and he has the same powers as root outside the jail,\n\
thus he can escape the jail and/or break stuff.\n\
case 'G':
opts.group = optarg;
break;
+ case 'O':
+ opts.overlaydir = optarg;
+ break;
+ case 'T':
+ opts.tmpoverlaysize = optarg;
+ break;
}
}
if (opts.namespace)
opts.namespace |= CLONE_NEWIPC | CLONE_NEWPID;
+ if (opts.tmpoverlaysize && strlen(opts.tmpoverlaysize) > 8) {
+ ERROR("size parameter too long: \"%s\"\n", opts.tmpoverlaysize);
+ return -1;
+ }
+
/* no <binary> param found */
if (argc - optind < 1) {
usage();
ERROR("failed to load dependencies\n");
return -1;
}
+ }
- if (opts.namespace && opts.seccomp && add_path_and_deps("libpreload-seccomp.so", 1, -1, 1)) {
- ERROR("failed to load libpreload-seccomp.so\n");
- return -1;
- }
+ if (opts.namespace && opts.seccomp && add_path_and_deps("libpreload-seccomp.so", 1, -1, 1)) {
+ ERROR("failed to load libpreload-seccomp.so\n");
+ return -1;
}
if (opts.name)
INSTANCE_ATTR_TERMTIMEOUT,
INSTANCE_ATTR_FACILITY,
INSTANCE_ATTR_EXTROOT,
+ INSTANCE_ATTR_OVERLAYDIR,
+ INSTANCE_ATTR_TMPOVERLAYSIZE,
__INSTANCE_ATTR_MAX
};
[INSTANCE_ATTR_TERMTIMEOUT] = { "term_timeout", BLOBMSG_TYPE_INT32 },
[INSTANCE_ATTR_FACILITY] = { "facility", BLOBMSG_TYPE_STRING },
[INSTANCE_ATTR_EXTROOT] = { "extroot", BLOBMSG_TYPE_STRING },
+ [INSTANCE_ATTR_OVERLAYDIR] = { "overlaydir", BLOBMSG_TYPE_STRING },
+ [INSTANCE_ATTR_TMPOVERLAYSIZE] = { "tmpoverlaysize", BLOBMSG_TYPE_STRING },
};
enum {
argv[argc++] = in->extroot;
}
+ if (in->overlaydir) {
+ argv[argc++] = "-O";
+ argv[argc++] = in->overlaydir;
+ }
+
+ if (in->tmpoverlaysize) {
+ argv[argc++] = "-T";
+ argv[argc++] = in->tmpoverlaysize;
+ }
+
blobmsg_list_for_each(&jail->mount, var) {
const char *type = blobmsg_data(var->data);
if (in->group)
jail->argc += 2;
- if (in->extroot) {
+ if (in->extroot)
+ jail->argc += 2;
+
+ if (in->overlaydir)
+ jail->argc += 2;
+
+ if (in->tmpoverlaysize)
jail->argc += 2;
- }
if (in->no_new_privs)
jail->argc++;
if (tb[INSTANCE_ATTR_EXTROOT])
in->extroot = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_EXTROOT]));
+ if (tb[INSTANCE_ATTR_OVERLAYDIR])
+ in->overlaydir = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_OVERLAYDIR]));
+
+ if (tb[INSTANCE_ATTR_TMPOVERLAYSIZE])
+ in->tmpoverlaysize = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_TMPOVERLAYSIZE]));
+
if (tb[INSTANCE_ATTR_PIDFILE]) {
char *pidfile = blobmsg_get_string(tb[INSTANCE_ATTR_PIDFILE]);
if (pidfile)
free(in->user);
free(in->group);
free(in->extroot);
+ free(in->overlaydir);
+ free(in->tmpoverlaysize);
free(in->jail.name);
free(in->jail.hostname);
free(in->seccomp);
blobmsg_add_string(b, "hostname", in->jail.hostname);
if (in->extroot)
blobmsg_add_string(b, "extroot", in->extroot);
+ if (in->overlaydir)
+ blobmsg_add_string(b, "overlaydir", in->overlaydir);
+ if (in->tmpoverlaysize)
+ blobmsg_add_string(b, "tmpoverlaysize", in->tmpoverlaysize);
+
blobmsg_add_u8(b, "procfs", in->jail.procfs);
blobmsg_add_u8(b, "sysfs", in->jail.sysfs);
blobmsg_add_u8(b, "ubus", in->jail.ubus);