Unverified Commit 5596585d by Stéphane Graber Committed by GitHub

Merge pull request #2125 from brauner/2018-02-02/add_namespace_configs

confile: add lxc.namespace.share.[namespace], lxc.namespace.keep, lxc.namespace.clone
parents dfb7073f 46186acd
...@@ -1426,14 +1426,73 @@ dev/null proc/kcore none bind,relative 0 0 ...@@ -1426,14 +1426,73 @@ dev/null proc/kcore none bind,relative 0 0
</refsect2> </refsect2>
<refsect2> <refsect2>
<title>Namespace Inheritance</title> <title>Namespaces</title>
<para> <para>
A namespace can be inherited from another container or process. A namespace can be cloned (<option>lxc.namespace.clone</option>),
kept (<option>lxc.namespace.keep</option>) or shared
(<option>lxc.namespace.share.[namespace identifier]</option>).
</para> </para>
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term> <term>
<option>lxc.namespace.[namespace identifier]</option> <option>lxc.namespace.clone</option>
</term>
<listitem>
<para>
Specify namespaces which the container is supposed to be created
with. The namespaces to create are specified as a space separated
list. Each namespace must correspond to one of the standard
namespace identifiers as seen in the
<filename>/proc/PID/ns</filename> directory.
When <option>lxc.namespace.clone</option> is not explicitly set all
namespaces supported by the kernel and the current configuration
will be used.
</para>
<para>
To create a new mount, net and ipc namespace set
<option>lxc.namespace.clone=mount net ipc</option>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>lxc.namespace.keep</option>
</term>
<listitem>
<para>
Specify namespaces which the container is supposed to inherit from
the process that created it. The namespaces to keep are specified as
a space separated list. Each namespace must correspond to one of the
standard namespace identifiers as seen in the
<filename>/proc/PID/ns</filename> directory.
The <option>lxc.namespace.keep</option> is a
blacklist option, i.e. it is useful when enforcing that containers
must keep a specific set of namespaces.
</para>
<para>
To keep the network, user and ipc namespace set
<option>lxc.namespace.keep=user net ipc</option>.
</para>
<para>
Note that sharing pid namespaces will likely not work with most init
systems.
</para>
<para>
Note that if the container requests a new user namespace and the
container wants to inherit the network namespace it needs to inherit
the user namespace as well.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>lxc.namespace.share.[namespace identifier]</option>
</term> </term>
<listitem> <listitem>
<para> <para>
...@@ -1445,22 +1504,22 @@ dev/null proc/kcore none bind,relative 0 0 ...@@ -1445,22 +1504,22 @@ dev/null proc/kcore none bind,relative 0 0
<para> <para>
To inherit the namespace from another process set the To inherit the namespace from another process set the
<option>lxc.namespace.[namespace identifier]</option> to the PID of <option>lxc.namespace.share.[namespace identifier]</option> to the PID of
the process, e.g. <option>lxc.namespace.net=42</option>. the process, e.g. <option>lxc.namespace.share.net=42</option>.
</para> </para>
<para> <para>
To inherit the namespace from another container set the To inherit the namespace from another container set the
<option>lxc.namespace.[namespace identifier]</option> to the name of <option>lxc.namespace.share.[namespace identifier]</option> to the name of
the container, e.g. <option>lxc.namespace.pid=c3</option>. the container, e.g. <option>lxc.namespace.share.pid=c3</option>.
</para> </para>
<para> <para>
To inherit the namespace from another container located in a To inherit the namespace from another container located in a
different path than the standard liblxc path set the different path than the standard liblxc path set the
<option>lxc.namespace.[namespace identifier]</option> to the full <option>lxc.namespace.share.[namespace identifier]</option> to the full
path to the container, e.g. path to the container, e.g.
<option>lxc.namespace.user=/opt/c3</option>. <option>lxc.namespace.share.user=/opt/c3</option>.
</para> </para>
<para> <para>
......
...@@ -2583,7 +2583,7 @@ struct lxc_conf *lxc_conf_init(void) ...@@ -2583,7 +2583,7 @@ struct lxc_conf *lxc_conf_init(void)
new->init_uid = 0; new->init_uid = 0;
new->init_gid = 0; new->init_gid = 0;
memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup)); memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup));
memset(&new->inherit_ns, 0, sizeof(char *) * LXC_NS_MAX); memset(&new->ns_share, 0, sizeof(char *) * LXC_NS_MAX);
return new; return new;
} }
......
...@@ -404,7 +404,11 @@ struct lxc_conf { ...@@ -404,7 +404,11 @@ struct lxc_conf {
*/ */
struct lxc_cgroup cgroup_meta; struct lxc_cgroup cgroup_meta;
char *inherit_ns[LXC_NS_MAX]; struct {
int ns_clone;
int ns_keep;
char *ns_share[LXC_NS_MAX];
};
/* init working directory */ /* init working directory */
char *init_cwd; char *init_cwd;
......
...@@ -107,7 +107,9 @@ lxc_config_define(monitor); ...@@ -107,7 +107,9 @@ lxc_config_define(monitor);
lxc_config_define(mount); lxc_config_define(mount);
lxc_config_define(mount_auto); lxc_config_define(mount_auto);
lxc_config_define(mount_fstab); lxc_config_define(mount_fstab);
lxc_config_define(namespace); lxc_config_define(namespace_clone);
lxc_config_define(namespace_keep);
lxc_config_define(namespace_share);
lxc_config_define(net); lxc_config_define(net);
lxc_config_define(net_flags); lxc_config_define(net_flags);
lxc_config_define(net_hwaddr); lxc_config_define(net_hwaddr);
...@@ -191,7 +193,9 @@ static struct lxc_config_t config[] = { ...@@ -191,7 +193,9 @@ static struct lxc_config_t config[] = {
{ "lxc.mount.auto", false, set_config_mount_auto, get_config_mount_auto, clr_config_mount_auto, }, { "lxc.mount.auto", false, set_config_mount_auto, get_config_mount_auto, clr_config_mount_auto, },
{ "lxc.mount.entry", false, set_config_mount, get_config_mount, clr_config_mount, }, { "lxc.mount.entry", false, set_config_mount, get_config_mount, clr_config_mount, },
{ "lxc.mount.fstab", false, set_config_mount_fstab, get_config_mount_fstab, clr_config_mount_fstab, }, { "lxc.mount.fstab", false, set_config_mount_fstab, get_config_mount_fstab, clr_config_mount_fstab, },
{ "lxc.namespace", false, set_config_namespace, get_config_namespace, clr_config_namespace, }, { "lxc.namespace.clone", false, set_config_namespace_clone, get_config_namespace_clone, clr_config_namespace_clone, },
{ "lxc.namespace.keep", false, set_config_namespace_keep, get_config_namespace_keep, clr_config_namespace_keep, },
{ "lxc.namespace.share", false, set_config_namespace_share, get_config_namespace_share, clr_config_namespace_share, },
/* [START]: REMOVE IN LXC 3.0 */ /* [START]: REMOVE IN LXC 3.0 */
{ "lxc.network.type", true, set_config_network_legacy_type, get_config_network_legacy_item, clr_config_network_legacy_item, }, { "lxc.network.type", true, set_config_network_legacy_type, get_config_network_legacy_item, clr_config_network_legacy_item, },
...@@ -2180,21 +2184,93 @@ static int set_config_uts_name(const char *key, const char *value, ...@@ -2180,21 +2184,93 @@ static int set_config_uts_name(const char *key, const char *value,
return 0; return 0;
} }
static int set_config_namespace(const char *key, const char *value, static int set_config_namespace_clone(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data) struct lxc_conf *lxc_conf, void *data)
{
char *ns, *nsptr, *token;
int cloneflag = 0;
char *saveptr = NULL;
if (lxc_config_value_empty(value))
return clr_config_namespace_clone(key, lxc_conf, data);
if (lxc_conf->ns_keep != 0) {
ERROR("%s - Cannot set both \"lxc.namespace.clone\" and "
"\"lxc.namespace.keep\"", strerror(EINVAL));
return -EINVAL;
}
ns = strdup(value);
if (!ns)
return -1;
nsptr = ns;
for (; (token = strtok_r(nsptr, " \t", &saveptr)); nsptr = NULL) {
token += lxc_char_left_gc(token, strlen(token));
token[lxc_char_right_gc(token, strlen(token))] = '\0';
cloneflag = lxc_namespace_2_cloneflag(token);
if (cloneflag < 0) {
free(ns);
return -EINVAL;
}
lxc_conf->ns_clone |= cloneflag;
}
free(ns);
return 0;
}
static int set_config_namespace_keep(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
char *ns, *nsptr, *token;
int cloneflag = 0;
char *saveptr = NULL;
if (lxc_config_value_empty(value))
return clr_config_namespace_keep(key, lxc_conf, data);
if (lxc_conf->ns_clone != 0) {
ERROR("%s - Cannot set both \"lxc.namespace.clone\" and "
"\"lxc.namespace.keep\"", strerror(EINVAL));
return -EINVAL;
}
ns = strdup(value);
if (!ns)
return -1;
nsptr = ns;
for (; (token = strtok_r(nsptr, " \t", &saveptr)); nsptr = NULL) {
token += lxc_char_left_gc(token, strlen(token));
token[lxc_char_right_gc(token, strlen(token))] = '\0';
cloneflag = lxc_namespace_2_cloneflag(token);
if (cloneflag < 0) {
free(ns);
return -EINVAL;
}
lxc_conf->ns_keep |= cloneflag;
}
free(ns);
return 0;
}
static int set_config_namespace_share(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{ {
int ns_idx; int ns_idx;
const char *namespace; const char *namespace;
if (lxc_config_value_empty(value)) if (lxc_config_value_empty(value))
return clr_config_namespace(key, lxc_conf, data); return clr_config_namespace_share(key, lxc_conf, data);
namespace = key + sizeof("lxc.namespace.") - 1; namespace = key + sizeof("lxc.namespace.share.") - 1;
ns_idx = lxc_namespace_2_ns_idx(namespace); ns_idx = lxc_namespace_2_ns_idx(namespace);
if (ns_idx < 0) if (ns_idx < 0)
return ns_idx; return ns_idx;
return set_config_string_item(&lxc_conf->inherit_ns[ns_idx], value); return set_config_string_item(&lxc_conf->ns_share[ns_idx], value);
} }
struct parse_line_conf { struct parse_line_conf {
...@@ -3614,8 +3690,46 @@ static int get_config_noop(const char *key, char *retv, int inlen, ...@@ -3614,8 +3690,46 @@ static int get_config_noop(const char *key, char *retv, int inlen,
return 0; return 0;
} }
static int get_config_namespace(const char *key, char *retv, int inlen, static int get_config_namespace_clone(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data) struct lxc_conf *c, void *data)
{
int i, len;
int fulllen = 0;
if (!retv)
inlen = 0;
else
memset(retv, 0, inlen);
for (i = 0; i < LXC_NS_MAX; i++) {
if (c->ns_clone & ns_info[i].clone_flag)
strprint(retv, inlen, "%s\n", ns_info[i].proc_name);
}
return fulllen;
}
static int get_config_namespace_keep(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{
int i, len;
int fulllen = 0;
if (!retv)
inlen = 0;
else
memset(retv, 0, inlen);
for (i = 0; i < LXC_NS_MAX; i++) {
if (c->ns_keep & ns_info[i].clone_flag)
strprint(retv, inlen, "%s\n", ns_info[i].proc_name);
}
return fulllen;
}
static int get_config_namespace_share(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{ {
int len, ns_idx; int len, ns_idx;
const char *namespace; const char *namespace;
...@@ -3626,12 +3740,12 @@ static int get_config_namespace(const char *key, char *retv, int inlen, ...@@ -3626,12 +3740,12 @@ static int get_config_namespace(const char *key, char *retv, int inlen,
else else
memset(retv, 0, inlen); memset(retv, 0, inlen);
namespace = key + sizeof("lxc.namespace.") - 1; namespace = key + sizeof("lxc.namespace.share.") - 1;
ns_idx = lxc_namespace_2_ns_idx(namespace); ns_idx = lxc_namespace_2_ns_idx(namespace);
if (ns_idx < 0) if (ns_idx < 0)
return ns_idx; return ns_idx;
strprint(retv, inlen, "%s", c->inherit_ns[ns_idx]); strprint(retv, inlen, "%s", c->ns_share[ns_idx]);
return fulllen; return fulllen;
} }
...@@ -4024,19 +4138,33 @@ static inline int clr_config_noop(const char *key, struct lxc_conf *c, ...@@ -4024,19 +4138,33 @@ static inline int clr_config_noop(const char *key, struct lxc_conf *c,
return 0; return 0;
} }
static int clr_config_namespace(const char *key, struct lxc_conf *lxc_conf, static int clr_config_namespace_clone(const char *key,
void *data) struct lxc_conf *lxc_conf, void *data)
{
lxc_conf->ns_clone = 0;
return 0;
}
static int clr_config_namespace_keep(const char *key, struct lxc_conf *lxc_conf,
void *data)
{
lxc_conf->ns_keep = 0;
return 0;
}
static int clr_config_namespace_share(const char *key,
struct lxc_conf *lxc_conf, void *data)
{ {
int ns_idx; int ns_idx;
const char *namespace; const char *namespace;
namespace = key + sizeof("lxc.namespace.") - 1; namespace = key + sizeof("lxc.namespace.share.") - 1;
ns_idx = lxc_namespace_2_ns_idx(namespace); ns_idx = lxc_namespace_2_ns_idx(namespace);
if (ns_idx < 0) if (ns_idx < 0)
return ns_idx; return ns_idx;
free(lxc_conf->inherit_ns[ns_idx]); free(lxc_conf->ns_share[ns_idx]);
lxc_conf->inherit_ns[ns_idx] = NULL; lxc_conf->ns_share[ns_idx] = NULL;
return 0; return 0;
} }
......
...@@ -1338,44 +1338,31 @@ static int lxc_recv_ttys_from_child(struct lxc_handler *handler) ...@@ -1338,44 +1338,31 @@ static int lxc_recv_ttys_from_child(struct lxc_handler *handler)
int resolve_clone_flags(struct lxc_handler *handler) int resolve_clone_flags(struct lxc_handler *handler)
{ {
handler->clone_flags = CLONE_NEWNS; int i;
struct lxc_conf *conf = handler->conf;
if (!handler->conf->inherit_ns[LXC_NS_USER]) {
if (!lxc_list_empty(&handler->conf->id_map))
handler->clone_flags |= CLONE_NEWUSER;
} else {
INFO("Inheriting user namespace");
}
if (!handler->conf->inherit_ns[LXC_NS_NET]) { for (i = 0; i < LXC_NS_MAX; i++) {
if (!lxc_requests_empty_network(handler)) if (conf->ns_keep != 0) {
handler->clone_flags |= CLONE_NEWNET; if ((conf->ns_keep & ns_info[i].clone_flag) == 0)
} else { handler->clone_flags |= ns_info[i].clone_flag;
INFO("Inheriting net namespace"); } else if (conf->ns_clone != 0) {
} if ((conf->ns_clone & ns_info[i].clone_flag) > 0)
handler->clone_flags |= ns_info[i].clone_flag;
} else {
if (i == LXC_NS_USER && lxc_list_empty(&handler->conf->id_map))
continue;
if (!handler->conf->inherit_ns[LXC_NS_IPC]) if (i == LXC_NS_NET && lxc_requests_empty_network(handler))
handler->clone_flags |= CLONE_NEWIPC; continue;
else
INFO("Inheriting ipc namespace");
if (!handler->conf->inherit_ns[LXC_NS_UTS]) handler->clone_flags |= ns_info[i].clone_flag;
handler->clone_flags |= CLONE_NEWUTS; }
else
INFO("Inheriting uts namespace");
if (!handler->conf->inherit_ns[LXC_NS_PID]) if (!conf->ns_share[i])
handler->clone_flags |= CLONE_NEWPID; continue;
else
INFO("Inheriting pid namespace");
if (cgns_supported()) { handler->clone_flags &= ~ns_info[i].clone_flag;
if (!handler->conf->inherit_ns[LXC_NS_CGROUP]) TRACE("Sharing %s namespace", ns_info[i].proc_name);
handler->clone_flags |= CLONE_NEWCGROUP;
else
INFO("Inheriting cgroup namespace");
} else if (handler->conf->inherit_ns[LXC_NS_CGROUP]) {
return -EINVAL;
} }
return 0; return 0;
...@@ -1440,10 +1427,10 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -1440,10 +1427,10 @@ static int lxc_spawn(struct lxc_handler *handler)
wants_to_map_ids = !lxc_list_empty(id_map); wants_to_map_ids = !lxc_list_empty(id_map);
for (i = 0; i < LXC_NS_MAX; i++) { for (i = 0; i < LXC_NS_MAX; i++) {
if (!conf->inherit_ns[i]) if (!conf->ns_share[i])
continue; continue;
handler->nsfd[i] = lxc_inherit_namespace(conf->inherit_ns[i], lxcpath, ns_info[i].proc_name); handler->nsfd[i] = lxc_inherit_namespace(conf->ns_share[i], lxcpath, ns_info[i].proc_name);
if (handler->nsfd[i] < 0) if (handler->nsfd[i] < 0)
return -1; return -1;
...@@ -1567,7 +1554,8 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -1567,7 +1554,8 @@ static int lxc_spawn(struct lxc_handler *handler)
* again. * again.
*/ */
if (wants_to_map_ids) { if (wants_to_map_ids) {
if (!handler->conf->inherit_ns[LXC_NS_USER]) { if (!handler->conf->ns_share[LXC_NS_USER] ||
(handler->conf->ns_keep & CLONE_NEWUSER) == 0) {
ret = lxc_map_ids(id_map, handler->pid); ret = lxc_map_ids(id_map, handler->pid);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to set up id mapping."); ERROR("Failed to set up id mapping.");
......
...@@ -311,13 +311,13 @@ bool lxc_setup_shared_ns(struct lxc_arguments *args, struct lxc_container *c) ...@@ -311,13 +311,13 @@ bool lxc_setup_shared_ns(struct lxc_arguments *args, struct lxc_container *c)
continue; continue;
if (i == LXC_NS_NET) if (i == LXC_NS_NET)
key = "lxc.namespace.net"; key = "lxc.namespace.share.net";
else if (i == LXC_NS_IPC) else if (i == LXC_NS_IPC)
key = "lxc.namespace.ipc"; key = "lxc.namespace.share.ipc";
else if (i == LXC_NS_UTS) else if (i == LXC_NS_UTS)
key = "lxc.namespace.uts"; key = "lxc.namespace.share.uts";
else if (i == LXC_NS_PID) else if (i == LXC_NS_PID)
key = "lxc.namespace.pid"; key = "lxc.namespace.share.pid";
else else
continue; continue;
......
...@@ -80,14 +80,14 @@ void *ns_sharing_wrapper(void *data) ...@@ -80,14 +80,14 @@ void *ns_sharing_wrapper(void *data)
} }
/* share ipc namespace by container name */ /* share ipc namespace by container name */
if (!c->set_config_item(c, "lxc.namespace.ipc", "owning-ns")) { if (!c->set_config_item(c, "lxc.namespace.share.ipc", "owning-ns")) {
lxc_error("Failed to set \"lxc.namespace.ipc=owning-ns\" for container \"%s\"\n", name); lxc_error("Failed to set \"lxc.namespace.share.ipc=owning-ns\" for container \"%s\"\n", name);
goto out; goto out;
} }
/* clear all network configuration */ /* clear all network configuration */
if (!c->set_config_item(c, "lxc.net", "")) { if (!c->set_config_item(c, "lxc.net", "")) {
lxc_error("Failed to set \"lxc.namespace.ipc=owning-ns\" for container \"%s\"\n", name); lxc_error("Failed to set \"lxc.namespace.share.ipc=owning-ns\" for container \"%s\"\n", name);
goto out; goto out;
} }
...@@ -98,8 +98,8 @@ void *ns_sharing_wrapper(void *data) ...@@ -98,8 +98,8 @@ void *ns_sharing_wrapper(void *data)
sprintf(owning_ns_init_pid, "%d", args->init_pid); sprintf(owning_ns_init_pid, "%d", args->init_pid);
/* share net namespace by pid */ /* share net namespace by pid */
if (!c->set_config_item(c, "lxc.namespace.net", owning_ns_init_pid)) { if (!c->set_config_item(c, "lxc.namespace.share.net", owning_ns_init_pid)) {
lxc_error("Failed to set \"lxc.namespace.net=%s\" for container \"%s\"\n", owning_ns_init_pid, name); lxc_error("Failed to set \"lxc.namespace.share.net=%s\" for container \"%s\"\n", owning_ns_init_pid, name);
goto out; goto out;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment