The network of a cell is set up from the outside and handed to the cell, like its mount tree. A capability over a network namespace has to be held in the user namespace that owns it, and that is never the user namespace of the cell. So no task of the cell can configure the network, not even its root user. Compare unshare(CLONE_NEWUSER | CLONE_NEWNET), which gives any caller CAP_NET_ADMIN over a network stack, and with it access to a large amount of code that was written for root. A cell does not get that. There are two ways to fill the slot: - CELL_SET_FD with the key "net" gives the cell an existing network namespace, set up however the builder wants. It requires CAP_SYS_ADMIN over the user namespace that owns the network namespace, as for the "root" slot. - CELL_SET_STRING with the value "new" creates a network namespace for the cell. It is owned by the user namespace that the cell was created in, so the builder can set it up. Until then it only contains a loopback device that is down. For now a cell whose slot is left empty also gets such a new namespace. The next patch changes that. A later patch adds a slot that lets the cell make selected changes to its network. A network namespace that is shared between cells can carry identities from one to the other. Only unix sockets know about cells. The builder has to take that into account. Signed-off-by: Josef Bacik --- kernel/cell/slots.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/kernel/cell/slots.c b/kernel/cell/slots.c index a96d2f262aa1..75855f2ee020 100644 --- a/kernel/cell/slots.c +++ b/kernel/cell/slots.c @@ -93,6 +93,36 @@ static int cell_make_net(struct cell *cell) return 0; } +/* "new": one that is made for the cell, for whoever builds the cell to set up. */ +static int cell_set_net_string(struct cell *cell, const char *val) +{ + if (strcmp(val, "new")) + return -EINVAL; + if (cell->net) + return -EBUSY; + return cell_make_net(cell); +} + +/* + * A network namespace to share. A file descriptor on one is no authority over + * it, so it takes CAP_SYS_ADMIN over its owner. That is half of what setns() + * asks for. The other half is about the namespaces of the caller, which do not + * change here. It goes on belonging to whoever it belongs to. + */ +static int cell_set_net(struct cell *cell, struct file *file) +{ + struct ns_common *ns = cell_ns_from_file(file, CLONE_NEWNET); + + if (IS_ERR(ns)) + return PTR_ERR(ns); + if (cell->net) + return -EBUSY; + if (!ns_capable(to_net_ns(ns)->user_ns, CAP_SYS_ADMIN)) + return -EPERM; + cell->net = get_net(to_net_ns(ns)); + return 0; +} + static int cell_set_ids_binary(struct cell *cell, const void __user *uvalue, size_t len) { @@ -131,6 +161,8 @@ static int cell_set_string(struct cell *cell, const char *key, const char *val) { if (!strcmp(key, "hostname")) return cell_set_hostname(cell, val); + if (!strcmp(key, "net")) + return cell_set_net_string(cell, val); return -EINVAL; } @@ -150,6 +182,8 @@ static int cell_set_fd(struct cell *cell, const char *key, struct file *file) return cell_set_budget(cell, file); if (!strcmp(key, "root")) return cell_set_root(cell, file); + if (!strcmp(key, "net")) + return cell_set_net(cell, file); return -EINVAL; } -- 2.55.0