#include "log.h"
#include <libubox/uloop.h>
+#include <libubus.h>
#define STACK_SIZE (1024 * 1024)
-#define OPT_ARGS "S:C:n:h:r:w:d:psulocU:G:"
+#define OPT_ARGS "S:C:n:h:r:w:d:psulocU:G:N"
+
+#define NAMESPACE_MOUNT (1U << 0)
+#define NAMESPACE_IPC (1U << 1)
+#define NAMESPACE_NET (1U << 2)
+#define NAMESPACE_PID (1U << 3)
+#define NAMESPACE_USER (1U << 4)
+#define NAMESPACE_UTS (1U << 5)
+#define NAMESPACE_CGROUP (1U << 6)
static struct {
char *name;
fprintf(stderr, " -n <name>\tthe name of the jail\n");
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, " -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");
kill(jail_process.pid, signo);
}
+static void netns_updown(bool start)
+{
+ struct ubus_context *ctx = ubus_connect(NULL);
+ static struct blob_buf req;
+ uint32_t id;
+ pid_t pid = getpid();
+
+ if (!ctx)
+ return;
+
+ blob_buf_init(&req, 0);
+ blobmsg_add_string(&req, "jail", opts.name);
+ blobmsg_add_u32(&req, "pid", pid);
+ blobmsg_add_u8(&req, "start", start);
+
+ if (ubus_lookup_id(ctx, "network", &id) ||
+ ubus_invoke(ctx, id, "netns_updown", req.head, NULL, NULL, 3000))
+ INFO("ubus request failed\n");
+
+ blob_buf_free(&req);
+ ubus_free(ctx);
+}
+
int main(int argc, char **argv)
{
sigset_t sigmask;
debug = atoi(optarg);
break;
case 'p':
- opts.namespace = 1;
+ opts.namespace |= NAMESPACE_MOUNT;
opts.procfs = 1;
break;
case 'o':
- opts.namespace = 1;
+ opts.namespace |= NAMESPACE_MOUNT;
opts.ronly = 1;
break;
case 's':
- opts.namespace = 1;
+ opts.namespace |= NAMESPACE_MOUNT;
opts.sysfs = 1;
break;
case 'S':
case 'n':
opts.name = optarg;
break;
+ case 'N':
+ opts.namespace |= NAMESPACE_NET;
+ break;
case 'h':
opts.hostname = optarg;
break;
case 'r':
- opts.namespace = 1;
+ opts.namespace |= NAMESPACE_MOUNT;
add_path_and_deps(optarg, 1, 0, 0);
break;
case 'w':
- opts.namespace = 1;
+ opts.namespace |= NAMESPACE_MOUNT;
add_path_and_deps(optarg, 0, 0, 0);
break;
case 'u':
- opts.namespace = 1;
+ opts.namespace |= NAMESPACE_MOUNT;
add_mount(ubus, 0, -1);
break;
case 'l':
- opts.namespace = 1;
+ opts.namespace |= NAMESPACE_MOUNT;
add_mount(log, 0, -1);
break;
case 'U':
}
if (opts.namespace) {
- add_mount("/dev/full", 0, -1);
- add_mount("/dev/null", 0, -1);
- add_mount("/dev/urandom", 0, -1);
- add_mount("/dev/zero", 0, -1);
-
- if (opts.user || opts.group) {
- add_mount("/etc/passwd", 0, -1);
- add_mount("/etc/group", 0, -1);
+ int flags = SIGCHLD | CLONE_NEWPID | CLONE_NEWIPC;
+
+ if (opts.namespace & NAMESPACE_MOUNT) {
+ flags |= CLONE_NEWNS;
+ add_mount("/dev/full", 0, -1);
+ add_mount("/dev/null", 0, -1);
+ add_mount("/dev/urandom", 0, -1);
+ add_mount("/dev/zero", 0, -1);
+
+ if (opts.user || opts.group) {
+ add_mount("/etc/passwd", 0, -1);
+ add_mount("/etc/group", 0, -1);
+ }
}
- int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | SIGCHLD;
if (opts.hostname)
flags |= CLONE_NEWUTS;
+
+ if (opts.namespace & NAMESPACE_NET) {
+ unshare(CLONE_NEWNET);
+ netns_updown(true);
+ };
+
jail_process.pid = clone(exec_jail, child_stack + STACK_SIZE, flags, NULL);
} else {
jail_process.pid = fork();
uloop_run();
}
uloop_done();
+ if (opts.namespace & NAMESPACE_NET)
+ netns_updown(false);
+
return jail_return_code;
} else if (jail_process.pid == 0) {
/* fork child process */
JAIL_ATTR_LOG,
JAIL_ATTR_RONLY,
JAIL_ATTR_MOUNT,
+ JAIL_ATTR_NETNS,
__JAIL_ATTR_MAX,
};
[JAIL_ATTR_LOG] = { "log", BLOBMSG_TYPE_BOOL },
[JAIL_ATTR_RONLY] = { "ronly", BLOBMSG_TYPE_BOOL },
[JAIL_ATTR_MOUNT] = { "mount", BLOBMSG_TYPE_TABLE },
+ [JAIL_ATTR_NETNS] = { "netns", BLOBMSG_TYPE_BOOL },
};
struct instance_netdev {
if (jail->ronly)
argv[argc++] = "-o";
+ if (jail->netns)
+ argv[argc++] = "-N";
+
blobmsg_list_for_each(&jail->mount, var) {
const char *type = blobmsg_data(var->data);
jail->ronly = blobmsg_get_bool(tb[JAIL_ATTR_RONLY]);
jail->argc++;
}
+ if (tb[JAIL_ATTR_NETNS]) {
+ jail->netns = blobmsg_get_bool(tb[JAIL_ATTR_NETNS]);
+ jail->argc++;
+ }
if (tb[JAIL_ATTR_MOUNT]) {
struct blob_attr *cur;
int rem;
blobmsg_add_u8(b, "ubus", in->jail.ubus);
blobmsg_add_u8(b, "log", in->jail.log);
blobmsg_add_u8(b, "ronly", in->jail.ronly);
+ blobmsg_add_u8(b, "netns", in->jail.netns);
blobmsg_close_table(b, r);
if (!avl_is_empty(&in->jail.mount.avl)) {
struct blobmsg_list_node *var;