From 58c12f74d82c68051471f9c98c86786018f17dae Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 4 Dec 2019 14:06:06 +0100 Subject: [PATCH] jail: add basic support for network namespaces Add new 'netns' flag for procd_add_jail to make ujail setup a new network namespace for the jailed service. Signed-off-by: Daniel Golle --- CMakeLists.txt | 2 +- jail/jail.c | 83 ++++++++++++++++++++++++++++++++++++---------- service/instance.c | 10 ++++++ service/instance.h | 1 + 4 files changed, 78 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a566acd..cff47cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,7 +105,7 @@ endif() IF(JAIL_SUPPORT) ADD_EXECUTABLE(ujail jail/jail.c jail/elf.c jail/fs.c jail/capabilities.c) -TARGET_LINK_LIBRARIES(ujail ${ubox} ${blobmsg_json}) +TARGET_LINK_LIBRARIES(ujail ${ubox} ${ubus} ${blobmsg_json}) INSTALL(TARGETS ujail RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} ) diff --git a/jail/jail.c b/jail/jail.c index c6096f8..2d23ad2 100644 --- a/jail/jail.c +++ b/jail/jail.c @@ -37,9 +37,18 @@ #include "log.h" #include +#include #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; @@ -224,6 +233,7 @@ static void usage(void) fprintf(stderr, " -n \tthe name of the jail\n"); fprintf(stderr, "namespace jail options:\n"); fprintf(stderr, " -h \tchange the hostname of the jail\n"); + fprintf(stderr, " -N\t\tjail has network namespace\n"); fprintf(stderr, " -r \treadonly files that should be staged\n"); fprintf(stderr, " -w \twriteable files that should be staged\n"); fprintf(stderr, " -p\t\tjail has /proc\n"); @@ -348,6 +358,29 @@ static void jail_handle_signal(int signo) 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; @@ -371,15 +404,15 @@ int main(int argc, char **argv) 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': @@ -395,23 +428,26 @@ int main(int argc, char **argv) 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': @@ -469,19 +505,29 @@ int main(int argc, char **argv) } 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(); @@ -498,6 +544,9 @@ int main(int argc, char **argv) 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 */ diff --git a/service/instance.c b/service/instance.c index 14da862..3b4e93a 100644 --- a/service/instance.c +++ b/service/instance.c @@ -99,6 +99,7 @@ enum { JAIL_ATTR_LOG, JAIL_ATTR_RONLY, JAIL_ATTR_MOUNT, + JAIL_ATTR_NETNS, __JAIL_ATTR_MAX, }; @@ -111,6 +112,7 @@ static const struct blobmsg_policy jail_attr[__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 { @@ -250,6 +252,9 @@ jail_run(struct service_instance *in, char **argv) 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); @@ -832,6 +837,10 @@ instance_jail_parse(struct service_instance *in, struct blob_attr *attr) 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; @@ -1218,6 +1227,7 @@ void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose) 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; diff --git a/service/instance.h b/service/instance.h index 42cc4be..e53c606 100644 --- a/service/instance.h +++ b/service/instance.h @@ -28,6 +28,7 @@ struct jail { bool ubus; bool log; bool ronly; + bool netns; char *name; char *hostname; struct blobmsg_list mount; -- 2.25.1