From 223797c313c0be4ea8e1cca64b3ad1215004c020 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 25 Aug 2021 18:38:06 +0200 Subject: [PATCH 01/15] conf: port rlimits to new list type Signed-off-by: Christian Brauner --- src/lxc/attach.c | 10 +++------- src/lxc/conf.c | 23 ++++++++++------------- src/lxc/conf.h | 6 ++++-- src/lxc/confile.c | 37 ++++++++++++++----------------------- src/lxc/start.c | 10 ++++------ 5 files changed, 35 insertions(+), 51 deletions(-) diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 4bfdf23cf..b1289e0eb 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -1668,13 +1668,9 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, } /* Setup resource limits */ - if (!lxc_list_empty(&conf->limits)) { - ret = setup_resource_limits(&conf->limits, pid); - if (ret < 0) - goto on_error; - - TRACE("Setup resource limits"); - } + ret = setup_resource_limits(conf, pid); + if (ret < 0) + goto on_error; if (options->attach_flags & LXC_ATTACH_TERMINAL) { ret = lxc_attach_terminal_mainloop_init(&terminal, &descr); diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 34cb24689..41c23967f 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -3249,15 +3249,15 @@ static int parse_resource(const char *res) return resid; } -int setup_resource_limits(struct lxc_list *limits, pid_t pid) +int setup_resource_limits(struct lxc_conf *conf, pid_t pid) { int resid; - struct lxc_list *it; struct lxc_limit *lim; - lxc_list_for_each (it, limits) { - lim = it->elem; + if (list_empty(&conf->limits)) + return 0; + list_for_each_entry(lim, &conf->limits, head) { resid = parse_resource(lim->resource); if (resid < 0) return log_error(-1, "Unknown resource %s", lim->resource); @@ -3272,6 +3272,7 @@ int setup_resource_limits(struct lxc_list *limits, pid_t pid) #endif } + TRACE("Setup resource limits"); return 0; } @@ -3388,7 +3389,7 @@ struct lxc_conf *lxc_conf_init(void) lxc_list_init(&new->includes); lxc_list_init(&new->aliens); lxc_list_init(&new->environment); - lxc_list_init(&new->limits); + INIT_LIST_HEAD(&new->limits); lxc_list_init(&new->sysctls); lxc_list_init(&new->procs); new->hooks_version = 0; @@ -4588,9 +4589,9 @@ static inline void lxc_clear_cgroups_devices(struct lxc_conf *conf) int lxc_clear_limits(struct lxc_conf *c, const char *key) { - struct lxc_list *it, *next; const char *k = NULL; bool all = false; + struct lxc_limit *lim, *nlim; if (strequal(key, "lxc.limit") || strequal(key, "lxc.prlimit")) all = true; @@ -4601,21 +4602,17 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key) else return ret_errno(EINVAL); - lxc_list_for_each_safe (it, &c->limits, next) { - struct lxc_limit *lim = it->elem; - + list_for_each_entry_safe(lim, nlim, &c->limits, head) { if (!all && !strequal(lim->resource, k)) continue; - lxc_list_del(it); - + list_del(&lim->head); free_disarm(lim->resource); free(lim); - free(it); } if (all) - lxc_list_init(&c->limits); + INIT_LIST_HEAD(&c->limits); return 0; } diff --git a/src/lxc/conf.h b/src/lxc/conf.h index e5b57737c..9de181d00 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -95,6 +95,7 @@ define_cleanup_function(struct lxc_cgroup *, free_lxc_cgroup); struct rlimit { unsigned long rlim_cur; unsigned long rlim_max; + struct list_head head; }; #endif @@ -106,6 +107,7 @@ struct rlimit { struct lxc_limit { char *resource; struct rlimit limit; + struct list_head head; }; static void free_lxc_limit(struct lxc_limit *ptr) @@ -468,7 +470,7 @@ struct lxc_conf { bool no_new_privs; /* RLIMIT_* limits */ - struct lxc_list limits; + struct list_head limits; /* Contains generic info about the cgroup configuration for this * container. Note that struct lxc_cgroup contains a union. It is only @@ -539,7 +541,7 @@ __hidden extern int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const c const char *lxcpath); __hidden extern int lxc_setup(struct lxc_handler *handler); __hidden extern int lxc_setup_parent(struct lxc_handler *handler); -__hidden extern int setup_resource_limits(struct lxc_list *limits, pid_t pid); +__hidden extern int setup_resource_limits(struct lxc_conf *conf, pid_t pid); __hidden extern int find_unmapped_nsid(const struct lxc_conf *conf, enum idtype idtype); __hidden extern int mapped_hostid(unsigned id, const struct lxc_conf *conf, enum idtype idtype); __hidden extern int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data, diff --git a/src/lxc/confile.c b/src/lxc/confile.c index d63b6b60a..2bf7dcd8d 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -2056,11 +2056,10 @@ static bool parse_limit_value(const char **value, rlim_t *res) static int set_config_prlimit(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { - __do_free struct lxc_list *list = NULL; - call_cleaner(free_lxc_limit) struct lxc_limit *elem = NULL; - struct lxc_list *iter; + call_cleaner(free_lxc_limit) struct lxc_limit *new_lim = NULL; struct rlimit limit; rlim_t limit_value; + struct lxc_limit *lim; if (lxc_config_value_empty(value)) return lxc_clear_limits(lxc_conf, key); @@ -2107,32 +2106,25 @@ static int set_config_prlimit(const char *key, const char *value, } /* find existing list element */ - lxc_list_for_each(iter, &lxc_conf->limits) { - struct lxc_limit *cur = iter->elem; - - if (!strequal(key, cur->resource)) + list_for_each_entry(lim, &lxc_conf->limits, head) { + if (!strequal(key, lim->resource)) continue; - cur->limit = limit; + lim->limit = limit; return 0; } - /* allocate list element */ - list = lxc_list_new(); - if (!list) + new_lim = zalloc(sizeof(*new_lim)); + if (!new_lim) return ret_errno(ENOMEM); - elem = zalloc(sizeof(*elem)); - if (!elem) + new_lim->resource = strdup(key); + if (!new_lim->resource) return ret_errno(ENOMEM); - elem->resource = strdup(key); - if (!elem->resource) - return ret_errno(ENOMEM); - - elem->limit = limit; - lxc_list_add_elem(list, move_ptr(elem));; - lxc_list_add_tail(&lxc_conf->limits, move_ptr(list)); + new_lim->limit = limit; + list_add_tail(&new_lim->head, &lxc_conf->limits); + move_ptr(new_lim); return 0; } @@ -4561,7 +4553,7 @@ static int get_config_prlimit(const char *key, char *retv, int inlen, { int fulllen = 0, len; bool get_all = false; - struct lxc_list *it; + struct lxc_limit *lim; if (!retv) inlen = 0; @@ -4575,11 +4567,10 @@ static int get_config_prlimit(const char *key, char *retv, int inlen, else return ret_errno(EINVAL); - lxc_list_for_each(it, &c->limits) { + list_for_each_entry(lim, &c->limits, head) { /* 2 colon separated 64 bit integers or the word 'unlimited' */ char buf[INTTYPE_TO_STRLEN(uint64_t) * 2 + 2]; int partlen; - struct lxc_limit *lim = it->elem; if (lim->limit.rlim_cur == RLIM_INFINITY) { memcpy(buf, "unlimited", STRLITERALLEN("unlimited") + 1); diff --git a/src/lxc/start.c b/src/lxc/start.c index 41f820279..1d4d22908 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1822,12 +1822,10 @@ static int lxc_spawn(struct lxc_handler *handler) goto out_delete_net; } - if (!lxc_list_empty(&conf->limits)) { - ret = setup_resource_limits(&conf->limits, handler->pid); - if (ret < 0) { - ERROR("Failed to setup resource limits"); - goto out_delete_net; - } + ret = setup_resource_limits(conf, handler->pid); + if (ret < 0) { + ERROR("Failed to setup resource limits"); + goto out_delete_net; } /* Tell the child to continue its initialization. */ From ba9f93472d0bbf054ed50f2161b768eb29abefc1 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 25 Aug 2021 18:47:51 +0200 Subject: [PATCH 02/15] conf: port sysctls to new list type Signed-off-by: Christian Brauner --- src/lxc/conf.c | 50 ++++++++++++++++++++++------------------------- src/lxc/conf.h | 5 +++-- src/lxc/confile.c | 36 +++++++++++++--------------------- 3 files changed, 40 insertions(+), 51 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 41c23967f..f4bb53c9f 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -3276,29 +3276,30 @@ int setup_resource_limits(struct lxc_conf *conf, pid_t pid) return 0; } -int setup_sysctl_parameters(struct lxc_list *sysctls) +int setup_sysctl_parameters(struct lxc_conf *conf) { __do_free char *tmp = NULL; - struct lxc_list *it; - struct lxc_sysctl *elem; int ret = 0; char filename[PATH_MAX] = {0}; + struct lxc_sysctl *sysctl, *nsysctl; - lxc_list_for_each (it, sysctls) { - elem = it->elem; - tmp = lxc_string_replace(".", "/", elem->key); + if (!list_empty(&conf->sysctls)) + return 0; + + list_for_each_entry_safe(sysctl, nsysctl, &conf->sysctls, head) { + tmp = lxc_string_replace(".", "/", sysctl->key); if (!tmp) - return log_error(-1, "Failed to replace key %s", elem->key); + return log_error(-1, "Failed to replace key %s", sysctl->key); ret = strnprintf(filename, sizeof(filename), "/proc/sys/%s", tmp); if (ret < 0) return log_error(-1, "Error setting up sysctl parameters path"); - ret = lxc_write_to_file(filename, elem->value, - strlen(elem->value), false, 0666); + ret = lxc_write_to_file(filename, sysctl->value, + strlen(sysctl->value), false, 0666); if (ret < 0) return log_error_errno(-1, errno, "Failed to setup sysctl parameters %s to %s", - elem->key, elem->value); + sysctl->key, sysctl->value); } return 0; @@ -3390,7 +3391,7 @@ struct lxc_conf *lxc_conf_init(void) lxc_list_init(&new->aliens); lxc_list_init(&new->environment); INIT_LIST_HEAD(&new->limits); - lxc_list_init(&new->sysctls); + INIT_LIST_HEAD(&new->sysctls); lxc_list_init(&new->procs); new->hooks_version = 0; for (i = 0; i < NUM_LXC_HOOKS; i++) @@ -4422,11 +4423,9 @@ int lxc_setup(struct lxc_handler *handler) * key. For e.g. net.ipv4.ip_forward translated to * /proc/sys/net/ipv4/ip_forward. */ - if (!lxc_list_empty(&lxc_conf->sysctls)) { - ret = setup_sysctl_parameters(&lxc_conf->sysctls); - if (ret < 0) - return log_error(-1, "Failed to setup sysctl parameters"); - } + ret = setup_sysctl_parameters(lxc_conf); + if (ret < 0) + return log_error(-1, "Failed to setup sysctl parameters"); if (!lxc_list_empty(&lxc_conf->keepcaps)) { if (!lxc_list_empty(&lxc_conf->caps)) @@ -4619,9 +4618,9 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key) int lxc_clear_sysctls(struct lxc_conf *c, const char *key) { - struct lxc_list *it, *next; const char *k = NULL; bool all = false; + struct lxc_sysctl *sysctl, *nsysctl; if (strequal(key, "lxc.sysctl")) all = true; @@ -4630,21 +4629,18 @@ int lxc_clear_sysctls(struct lxc_conf *c, const char *key) else return -1; - lxc_list_for_each_safe(it, &c->sysctls, next) { - struct lxc_sysctl *elem = it->elem; - - if (!all && !strequal(elem->key, k)) + list_for_each_entry_safe(sysctl, nsysctl, &c->sysctls, head) { + if (!all && !strequal(sysctl->key, k)) continue; - lxc_list_del(it); - free(elem->key); - free(elem->value); - free(elem); - free(it); + list_del(&sysctl->head); + free(sysctl->key); + free(sysctl->value); + free(sysctl); } if (all) - lxc_list_init(&c->sysctls); + INIT_LIST_HEAD(&c->sysctls); return 0; } diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 9de181d00..59cbce602 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -132,6 +132,7 @@ enum idtype { struct lxc_sysctl { char *key; char *value; + struct list_head head; }; static void free_lxc_sysctl(struct lxc_sysctl *ptr) @@ -492,7 +493,7 @@ struct lxc_conf { struct list_head state_clients; /* sysctls */ - struct lxc_list sysctls; + struct list_head sysctls; /* procs */ struct lxc_list procs; @@ -572,7 +573,7 @@ static inline bool lxc_wants_cap(int cap, struct lxc_conf *conf) return !in_caplist(cap, &conf->caps); } -__hidden extern int setup_sysctl_parameters(struct lxc_list *sysctls); +__hidden extern int setup_sysctl_parameters(struct lxc_conf *conf); __hidden extern int lxc_clear_sysctls(struct lxc_conf *c, const char *key); __hidden extern int setup_proc_filesystem(struct lxc_list *procs, pid_t pid); __hidden extern int lxc_clear_procs(struct lxc_conf *c, const char *key); diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 2bf7dcd8d..4d3437d6d 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -2132,9 +2132,8 @@ static int set_config_prlimit(const char *key, const char *value, static int set_config_sysctl(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { - __do_free struct lxc_list *sysctl_list = NULL; call_cleaner(free_lxc_sysctl) struct lxc_sysctl *sysctl_elem = NULL; - struct lxc_list *iter; + struct lxc_sysctl *sysctl, *nsysctl; if (lxc_config_value_empty(value)) return clr_config_sysctl(key, lxc_conf, NULL); @@ -2147,28 +2146,22 @@ static int set_config_sysctl(const char *key, const char *value, return ret_errno(EINVAL); /* find existing list element */ - lxc_list_for_each(iter, &lxc_conf->sysctls) { + list_for_each_entry_safe(sysctl, nsysctl, &lxc_conf->sysctls, head) { __do_free char *replace_value = NULL; - struct lxc_sysctl *cur = iter->elem; - if (!strequal(key, cur->key)) + if (!strequal(key, sysctl->key)) continue; replace_value = strdup(value); if (!replace_value) return ret_errno(EINVAL); - free(cur->value); - cur->value = move_ptr(replace_value); + free(sysctl->value); + sysctl->value = move_ptr(replace_value); return 0; } - /* allocate list element */ - sysctl_list = lxc_list_new(); - if (!sysctl_list) - return ret_errno(ENOMEM); - sysctl_elem = zalloc(sizeof(*sysctl_elem)); if (!sysctl_elem) return ret_errno(ENOMEM); @@ -2181,8 +2174,8 @@ static int set_config_sysctl(const char *key, const char *value, if (!sysctl_elem->value) return ret_errno(ENOMEM); - lxc_list_add_elem(sysctl_list, move_ptr(sysctl_elem)); - lxc_list_add_tail(&lxc_conf->sysctls, move_ptr(sysctl_list)); + list_add_tail(&sysctl_elem->head, &lxc_conf->sysctls); + move_ptr(sysctl_elem); return 0; } @@ -4607,10 +4600,10 @@ static int get_config_prlimit(const char *key, char *retv, int inlen, static int get_config_sysctl(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { - int len; - struct lxc_list *it; int fulllen = 0; bool get_all = false; + int len; + struct lxc_sysctl *sysctl; if (!retv) inlen = 0; @@ -4624,13 +4617,12 @@ static int get_config_sysctl(const char *key, char *retv, int inlen, else return ret_errno(EINVAL); - lxc_list_for_each(it, &c->sysctls) { - struct lxc_sysctl *elem = it->elem; + list_for_each_entry(sysctl, &c->sysctls, head) { if (get_all) { - strprint(retv, inlen, "lxc.sysctl.%s = %s\n", elem->key, - elem->value); - } else if (strequal(elem->key, key)) { - strprint(retv, inlen, "%s", elem->value); + strprint(retv, inlen, "lxc.sysctl.%s = %s\n", sysctl->key, + sysctl->value); + } else if (strequal(sysctl->key, key)) { + strprint(retv, inlen, "%s", sysctl->value); } } From 91d04bf9db0218f3efd801c538158f488bea6d81 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 25 Aug 2021 18:55:10 +0200 Subject: [PATCH 03/15] conf: port procs to new list type Signed-off-by: Christian Brauner --- src/lxc/attach.c | 10 +++------- src/lxc/conf.c | 36 ++++++++++++++++++------------------ src/lxc/conf.h | 5 +++-- src/lxc/confile.c | 31 ++++++++++++------------------- src/lxc/start.c | 8 ++++---- 5 files changed, 40 insertions(+), 50 deletions(-) diff --git a/src/lxc/attach.c b/src/lxc/attach.c index b1289e0eb..396001963 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -1659,13 +1659,9 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, goto on_error; /* Setup /proc limits */ - if (!lxc_list_empty(&conf->procs)) { - ret = setup_proc_filesystem(&conf->procs, pid); - if (ret < 0) - goto on_error; - - TRACE("Setup /proc/%d settings", pid); - } + ret = setup_proc_filesystem(conf, pid); + if (ret < 0) + goto on_error; /* Setup resource limits */ ret = setup_resource_limits(conf, pid); diff --git a/src/lxc/conf.c b/src/lxc/conf.c index f4bb53c9f..d048874ef 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -3305,30 +3305,33 @@ int setup_sysctl_parameters(struct lxc_conf *conf) return 0; } -int setup_proc_filesystem(struct lxc_list *procs, pid_t pid) +int setup_proc_filesystem(struct lxc_conf *conf, pid_t pid) { __do_free char *tmp = NULL; - struct lxc_list *it; - struct lxc_proc *elem; int ret = 0; char filename[PATH_MAX] = {0}; + struct lxc_proc *proc; - lxc_list_for_each (it, procs) { - elem = it->elem; - tmp = lxc_string_replace(".", "/", elem->filename); + if (!list_empty(&conf->procs)) + return 0; + + list_for_each_entry(proc, &conf->procs, head) { + tmp = lxc_string_replace(".", "/", proc->filename); if (!tmp) - return log_error(-1, "Failed to replace key %s", elem->filename); + return log_error(-1, "Failed to replace key %s", proc->filename); ret = strnprintf(filename, sizeof(filename), "/proc/%d/%s", pid, tmp); if (ret < 0) return log_error(-1, "Error setting up proc filesystem path"); - ret = lxc_write_to_file(filename, elem->value, - strlen(elem->value), false, 0666); + ret = lxc_write_to_file(filename, proc->value, + strlen(proc->value), false, 0666); if (ret < 0) - return log_error_errno(-1, errno, "Failed to setup proc filesystem %s to %s", elem->filename, elem->value); + return log_error_errno(-1, errno, "Failed to setup proc filesystem %s to %s", + proc->filename, proc->value); } + TRACE("Setup /proc/%d settings", pid); return 0; } @@ -3392,7 +3395,7 @@ struct lxc_conf *lxc_conf_init(void) lxc_list_init(&new->environment); INIT_LIST_HEAD(&new->limits); INIT_LIST_HEAD(&new->sysctls); - lxc_list_init(&new->procs); + INIT_LIST_HEAD(&new->procs); new->hooks_version = 0; for (i = 0; i < NUM_LXC_HOOKS; i++) lxc_list_init(&new->hooks[i]); @@ -4647,9 +4650,9 @@ int lxc_clear_sysctls(struct lxc_conf *c, const char *key) int lxc_clear_procs(struct lxc_conf *c, const char *key) { - struct lxc_list *it, *next; const char *k = NULL; bool all = false; + struct lxc_proc *proc, *nproc; if (strequal(key, "lxc.proc")) all = true; @@ -4658,21 +4661,18 @@ int lxc_clear_procs(struct lxc_conf *c, const char *key) else return -1; - lxc_list_for_each_safe(it, &c->procs, next) { - struct lxc_proc *proc = it->elem; - + list_for_each_entry_safe(proc, nproc, &c->procs, head) { if (!all && !strequal(proc->filename, k)) continue; - lxc_list_del(it); + list_del(&proc->head); free(proc->filename); free(proc->value); free(proc); - free(it); } if (all) - lxc_list_init(&c->procs); + INIT_LIST_HEAD(&c->procs); return 0; } diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 59cbce602..00b4a5849 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -153,6 +153,7 @@ define_cleanup_function(struct lxc_sysctl *, free_lxc_sysctl); struct lxc_proc { char *filename; char *value; + struct list_head head; }; static void free_lxc_proc(struct lxc_proc *ptr) @@ -496,7 +497,7 @@ struct lxc_conf { struct list_head sysctls; /* procs */ - struct lxc_list procs; + struct list_head procs; struct shmount { /* Absolute path to the shared mount point on the host */ @@ -575,7 +576,7 @@ static inline bool lxc_wants_cap(int cap, struct lxc_conf *conf) __hidden extern int setup_sysctl_parameters(struct lxc_conf *conf); __hidden extern int lxc_clear_sysctls(struct lxc_conf *c, const char *key); -__hidden extern int setup_proc_filesystem(struct lxc_list *procs, pid_t pid); +__hidden extern int setup_proc_filesystem(struct lxc_conf *conf, pid_t pid); __hidden extern int lxc_clear_procs(struct lxc_conf *c, const char *key); __hidden extern int lxc_clear_apparmor_raw(struct lxc_conf *c); __hidden extern int lxc_clear_namespace(struct lxc_conf *c); diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 4d3437d6d..97b822b1a 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -2183,8 +2183,7 @@ static int set_config_sysctl(const char *key, const char *value, static int set_config_proc(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { - __do_free struct lxc_list *proclist = NULL; - call_cleaner(free_lxc_proc) struct lxc_proc *procelem = NULL; + call_cleaner(free_lxc_proc) struct lxc_proc *new_proc = NULL; const char *subkey; if (lxc_config_value_empty(value)) @@ -2197,24 +2196,20 @@ static int set_config_proc(const char *key, const char *value, if (*subkey == '\0') return ret_errno(EINVAL); - proclist = lxc_list_new(); - if (!proclist) + new_proc = zalloc(sizeof(*new_proc)); + if (!new_proc) return ret_errno(ENOMEM); - procelem = zalloc(sizeof(*procelem)); - if (!procelem) + new_proc->filename = strdup(subkey); + if (!new_proc->filename) return ret_errno(ENOMEM); - procelem->filename = strdup(subkey); - if (!procelem->filename) + new_proc->value = strdup(value); + if (!new_proc->value) return ret_errno(ENOMEM); - procelem->value = strdup(value); - if (!procelem->value) - return ret_errno(ENOMEM); - - proclist->elem = move_ptr(procelem); - lxc_list_add_tail(&lxc_conf->procs, move_ptr(proclist)); + list_add_tail(&new_proc->head, &lxc_conf->procs); + move_ptr(new_proc); return 0; } @@ -4632,10 +4627,10 @@ static int get_config_sysctl(const char *key, char *retv, int inlen, static int get_config_proc(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { - struct lxc_list *it; - int len; int fulllen = 0; bool get_all = false; + int len; + struct lxc_proc *proc; if (!retv) inlen = 0; @@ -4649,9 +4644,7 @@ static int get_config_proc(const char *key, char *retv, int inlen, else return ret_errno(EINVAL); - lxc_list_for_each(it, &c->procs) { - struct lxc_proc *proc = it->elem; - + list_for_each_entry(proc, &c->procs, head) { if (get_all) { strprint(retv, inlen, "lxc.proc.%s = %s\n", proc->filename, proc->value); diff --git a/src/lxc/start.c b/src/lxc/start.c index 1d4d22908..4f09e4e5c 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1816,10 +1816,10 @@ static int lxc_spawn(struct lxc_handler *handler) } } - if (!lxc_list_empty(&conf->procs)) { - ret = setup_proc_filesystem(&conf->procs, handler->pid); - if (ret < 0) - goto out_delete_net; + ret = setup_proc_filesystem(conf, handler->pid); + if (ret < 0) { + ERROR("Failed to setup procfs limits"); + goto out_delete_net; } ret = setup_resource_limits(conf, handler->pid); From c9dbb8edf972182c8b046ea6161d5e48e914cd01 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 25 Aug 2021 19:20:57 +0200 Subject: [PATCH 04/15] conf: port cgroup settings to new list type Signed-off-by: Christian Brauner --- src/lxc/cgroups/cgfsng.c | 57 +++++++++++------------------ src/lxc/conf.c | 79 ++++++++++++---------------------------- src/lxc/conf.h | 8 ++-- src/lxc/confile.c | 50 +++++++++++-------------- 4 files changed, 72 insertions(+), 122 deletions(-) diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c index 54b298910..23aef495c 100644 --- a/src/lxc/cgroups/cgfsng.c +++ b/src/lxc/cgroups/cgfsng.c @@ -2707,11 +2707,8 @@ __cgfsng_ops static bool cgfsng_setup_limits_legacy(struct cgroup_ops *ops, struct lxc_conf *conf, bool do_devices) { - __do_free struct lxc_list *sorted_cgroup_settings = NULL; - struct lxc_list *cgroup_settings = &conf->cgroup; - struct lxc_list *iterator, *next; - struct lxc_cgroup *cg; - bool ret = false; + struct list_head *cgroup_settings; + struct lxc_cgroup *cgroup; if (!ops) return ret_set_errno(false, ENOENT); @@ -2720,7 +2717,7 @@ __cgfsng_ops static bool cgfsng_setup_limits_legacy(struct cgroup_ops *ops, return ret_set_errno(false, EINVAL); cgroup_settings = &conf->cgroup; - if (lxc_list_empty(cgroup_settings)) + if (list_empty(cgroup_settings)) return true; if (!ops->hierarchies) @@ -2729,35 +2726,23 @@ __cgfsng_ops static bool cgfsng_setup_limits_legacy(struct cgroup_ops *ops, if (pure_unified_layout(ops)) return log_warn_errno(true, EINVAL, "Ignoring legacy cgroup limits on pure cgroup2 system"); - sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings); - if (!sorted_cgroup_settings) - return false; - - lxc_list_for_each(iterator, sorted_cgroup_settings) { - cg = iterator->elem; - - if (do_devices == strnequal("devices", cg->subsystem, 7)) { - if (cg_legacy_set_data(ops, cg->subsystem, cg->value, strnequal("cpuset", cg->subsystem, 6))) { + sort_cgroup_settings(conf); + list_for_each_entry(cgroup, cgroup_settings, head) { + if (do_devices == strnequal("devices", cgroup->subsystem, 7)) { + if (cg_legacy_set_data(ops, cgroup->subsystem, cgroup->value, strnequal("cpuset", cgroup->subsystem, 6))) { if (do_devices && (errno == EACCES || errno == EPERM)) { - SYSWARN("Failed to set \"%s\" to \"%s\"", cg->subsystem, cg->value); + SYSWARN("Failed to set \"%s\" to \"%s\"", cgroup->subsystem, cgroup->value); continue; } - SYSERROR("Failed to set \"%s\" to \"%s\"", cg->subsystem, cg->value); - goto out; + SYSERROR("Failed to set \"%s\" to \"%s\"", cgroup->subsystem, cgroup->value); + return false; } - DEBUG("Set controller \"%s\" set to \"%s\"", cg->subsystem, cg->value); + DEBUG("Set controller \"%s\" set to \"%s\"", cgroup->subsystem, cgroup->value); } } - ret = true; INFO("Limits for the legacy cgroup hierarchies have been setup"); -out: - lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) { - lxc_list_del(iterator); - free(iterator); - } - - return ret; + return true; } /* @@ -2793,9 +2778,10 @@ static int bpf_device_cgroup_prepare(struct cgroup_ops *ops, __cgfsng_ops static bool cgfsng_setup_limits(struct cgroup_ops *ops, struct lxc_handler *handler) { - struct lxc_list *cgroup_settings, *iterator; + struct list_head *cgroup_settings; struct hierarchy *h; struct lxc_conf *conf; + struct lxc_cgroup *cgroup; if (!ops) return ret_set_errno(false, ENOENT); @@ -2811,7 +2797,7 @@ __cgfsng_ops static bool cgfsng_setup_limits(struct cgroup_ops *ops, conf = handler->conf; cgroup_settings = &conf->cgroup2; - if (lxc_list_empty(cgroup_settings)) + if (list_empty(cgroup_settings)) return true; if (!pure_unified_layout(ops)) @@ -2821,18 +2807,17 @@ __cgfsng_ops static bool cgfsng_setup_limits(struct cgroup_ops *ops, return false; h = ops->unified; - lxc_list_for_each (iterator, cgroup_settings) { - struct lxc_cgroup *cg = iterator->elem; + list_for_each_entry(cgroup, cgroup_settings, head) { int ret; - if (strnequal("devices", cg->subsystem, 7)) - ret = bpf_device_cgroup_prepare(ops, conf, cg->subsystem, cg->value); + if (strnequal("devices", cgroup->subsystem, 7)) + ret = bpf_device_cgroup_prepare(ops, conf, cgroup->subsystem, cgroup->value); else - ret = lxc_write_openat(h->path_lim, cg->subsystem, cg->value, strlen(cg->value)); + ret = lxc_write_openat(h->path_lim, cgroup->subsystem, cgroup->value, strlen(cgroup->value)); if (ret < 0) - return log_error_errno(false, errno, "Failed to set \"%s\" to \"%s\"", cg->subsystem, cg->value); + return log_error_errno(false, errno, "Failed to set \"%s\" to \"%s\"", cgroup->subsystem, cgroup->value); - TRACE("Set \"%s\" to \"%s\"", cg->subsystem, cg->value); + TRACE("Set \"%s\" to \"%s\"", cgroup->subsystem, cgroup->value); } return log_info(true, "Limits for the unified cgroup hierarchy have been setup"); diff --git a/src/lxc/conf.c b/src/lxc/conf.c index d048874ef..f0c6c74be 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -3379,8 +3379,8 @@ struct lxc_conf *lxc_conf_init(void) new->rootfs.fd_path_pin = -EBADF; new->rootfs.dfd_idmapped = -EBADF; new->logfd = -1; - lxc_list_init(&new->cgroup); - lxc_list_init(&new->cgroup2); + INIT_LIST_HEAD(&new->cgroup); + INIT_LIST_HEAD(&new->cgroup2); /* Block ("allowlist") all devices by default. */ new->bpf_devices.list_type = LXC_BPF_DEVICE_CGROUP_ALLOWLIST; INIT_LIST_HEAD(&(new->bpf_devices).devices); @@ -4538,11 +4538,12 @@ int lxc_clear_namespace(struct lxc_conf *c) int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version) { - char *global_token, *namespaced_token; - size_t namespaced_token_len; - struct lxc_list *it, *next, *list; const char *k = key; bool all = false; + char *global_token, *namespaced_token; + size_t namespaced_token_len; + struct list_head *list; + struct lxc_cgroup *cgroup, *ncgroup; if (version == CGROUP2_SUPER_MAGIC) { global_token = "lxc.cgroup2"; @@ -4565,21 +4566,18 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version) else return ret_errno(EINVAL); - lxc_list_for_each_safe(it, list, next) { - struct lxc_cgroup *cg = it->elem; - - if (!all && !strequal(cg->subsystem, k)) + list_for_each_entry_safe(cgroup, ncgroup, list, head) { + if (!all && !strequal(cgroup->subsystem, k)) continue; - lxc_list_del(it); - free(cg->subsystem); - free(cg->value); - free(cg); - free(it); + list_del(&cgroup->head); + free(cgroup->subsystem); + free(cgroup->value); + free(cgroup); } if (all) - lxc_list_init(list); + INIT_LIST_HEAD(list); return 0; } @@ -5817,54 +5815,25 @@ void suggest_default_idmap(void) ERROR("lxc.idmap = g 0 %u %u", gid, grange); } -static void free_cgroup_settings(struct lxc_list *result) -{ - struct lxc_list *iterator, *next; - - lxc_list_for_each_safe (iterator, result, next) { - lxc_list_del(iterator); - free_disarm(iterator); - } - free_disarm(result); -} - /* Return the list of cgroup_settings sorted according to the following rules * 1. Put memory.limit_in_bytes before memory.memsw.limit_in_bytes */ -struct lxc_list *sort_cgroup_settings(struct lxc_list *cgroup_settings) +void sort_cgroup_settings(struct lxc_conf *conf) { - struct lxc_list *result; - struct lxc_cgroup *cg = NULL; - struct lxc_list *it = NULL, *item = NULL, *memsw_limit = NULL; - - result = lxc_list_new(); - if (!result) - return NULL; - lxc_list_init(result); + struct lxc_cgroup *cgroup, *memsw_limit, *ncgroup; /* Iterate over the cgroup settings and copy them to the output list. */ - lxc_list_for_each (it, cgroup_settings) { - item = zalloc(sizeof(*item)); - if (!item) { - free_cgroup_settings(result); - return NULL; - } - - item->elem = it->elem; - cg = it->elem; - if (strequal(cg->subsystem, "memory.memsw.limit_in_bytes")) { + list_for_each_entry_safe(cgroup, ncgroup, &conf->cgroup, head) { + if (strequal(cgroup->subsystem, "memory.memsw.limit_in_bytes")) { /* Store the memsw_limit location */ - memsw_limit = item; - } else if (strequal(cg->subsystem, "memory.limit_in_bytes") && - memsw_limit != NULL) { - /* lxc.cgroup.memory.memsw.limit_in_bytes is found + memsw_limit = cgroup; + } else if (memsw_limit && strequal(cgroup->subsystem, "memory.limit_in_bytes")) { + /* + * lxc.cgroup.memory.memsw.limit_in_bytes is found * before lxc.cgroup.memory.limit_in_bytes, swap these - * two items */ - item->elem = memsw_limit->elem; - memsw_limit->elem = it->elem; + * two items. + */ + list_swap(&memsw_limit->head, &cgroup->head); } - lxc_list_add_tail(result, item); } - - return result; } diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 00b4a5849..e8d776cdc 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -78,6 +78,8 @@ struct lxc_cgroup { bool relative; }; }; + + struct list_head head; }; static void free_lxc_cgroup(struct lxc_cgroup *ptr) @@ -344,8 +346,8 @@ struct lxc_conf { struct utsname *utsname; struct { - struct lxc_list cgroup; - struct lxc_list cgroup2; + struct list_head cgroup; + struct list_head cgroup2; struct bpf_devices bpf_devices; }; @@ -557,7 +559,7 @@ __hidden extern int parse_mount_attrs(struct lxc_mount_options *opts, const char __hidden extern void tmp_proc_unmount(struct lxc_conf *lxc_conf); __hidden extern void suggest_default_idmap(void); __hidden extern FILE *make_anonymous_mount_file(struct lxc_list *mount, bool include_nesting_helpers); -__hidden extern struct lxc_list *sort_cgroup_settings(struct lxc_list *cgroup_settings); +__hidden extern void sort_cgroup_settings(struct lxc_conf *conf); __hidden extern int run_script(const char *name, const char *section, const char *script, ...); __hidden extern int run_script_argv(const char *name, unsigned int hook_version, const char *section, const char *script, const char *hookname, char **argsin); diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 97b822b1a..513b917d9 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -1858,8 +1858,7 @@ static int set_config_signal_stop(const char *key, const char *value, static int __set_config_cgroup_controller(const char *key, const char *value, struct lxc_conf *lxc_conf, int version) { - __do_free struct lxc_list *cglist = NULL; - call_cleaner(free_lxc_cgroup) struct lxc_cgroup *cgelem = NULL; + call_cleaner(free_lxc_cgroup) struct lxc_cgroup *new_cgroup = NULL; const char *subkey, *token; size_t token_len; @@ -1883,31 +1882,25 @@ static int __set_config_cgroup_controller(const char *key, const char *value, if (*subkey == '\0') return ret_errno(EINVAL); - cglist = lxc_list_new(); - if (!cglist) + new_cgroup = zalloc(sizeof(*new_cgroup)); + if (!new_cgroup) return ret_errno(ENOMEM); - cgelem = zalloc(sizeof(*cgelem)); - if (!cgelem) + new_cgroup->subsystem = strdup(subkey); + if (!new_cgroup->subsystem) return ret_errno(ENOMEM); - cgelem->subsystem = strdup(subkey); - if (!cgelem->subsystem) + new_cgroup->value = strdup(value); + if (!new_cgroup->value) return ret_errno(ENOMEM); - cgelem->value = strdup(value); - if (!cgelem->value) - return ret_errno(ENOMEM); - - cgelem->version = version; - - lxc_list_add_elem(cglist, move_ptr(cgelem)); + new_cgroup->version = version; if (version == CGROUP2_SUPER_MAGIC) - lxc_list_add_tail(&lxc_conf->cgroup2, cglist); + list_add_tail(&new_cgroup->head, &lxc_conf->cgroup2); else - lxc_list_add_tail(&lxc_conf->cgroup, cglist); - move_ptr(cglist); + list_add_tail(&new_cgroup->head, &lxc_conf->cgroup); + move_ptr(new_cgroup); return 0; } @@ -3842,12 +3835,13 @@ static int __get_config_cgroup_controller(const char *key, char *retv, int inlen, struct lxc_conf *c, int version) { + int fulllen = 0; + bool get_all = false; int len; size_t namespaced_token_len; char *global_token, *namespaced_token; - struct lxc_list *it; - int fulllen = 0; - bool get_all = false; + struct list_head *list; + struct lxc_cgroup *cgroup; if (!retv) inlen = 0; @@ -3858,10 +3852,12 @@ static int __get_config_cgroup_controller(const char *key, char *retv, global_token = "lxc.cgroup2"; namespaced_token = "lxc.cgroup2."; namespaced_token_len = STRLITERALLEN("lxc.cgroup2."); + list = &c->cgroup2; } else if (version == CGROUP_SUPER_MAGIC) { global_token = "lxc.cgroup"; namespaced_token = "lxc.cgroup."; namespaced_token_len = STRLITERALLEN("lxc.cgroup."); + list = &c->cgroup; } else { return ret_errno(EINVAL); } @@ -3873,17 +3869,15 @@ static int __get_config_cgroup_controller(const char *key, char *retv, else return ret_errno(EINVAL); - lxc_list_for_each(it, &c->cgroup) { - struct lxc_cgroup *cg = it->elem; - + list_for_each_entry(cgroup, list, head) { if (get_all) { - if (version != cg->version) + if (version != cgroup->version) continue; strprint(retv, inlen, "%s.%s = %s\n", global_token, - cg->subsystem, cg->value); - } else if (strequal(cg->subsystem, key)) { - strprint(retv, inlen, "%s\n", cg->value); + cgroup->subsystem, cgroup->value); + } else if (strequal(cgroup->subsystem, key)) { + strprint(retv, inlen, "%s\n", cgroup->value); } } From 0589d744f699a4efb98079f33ddeece6f5d7c8b9 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 25 Aug 2021 22:38:18 +0200 Subject: [PATCH 05/15] conf: port id_map to new list type Signed-off-by: Christian Brauner --- src/lxc/cgroups/cgfsng.c | 10 +- src/lxc/cmd/lxc_usernsexec.c | 19 +-- src/lxc/conf.c | 242 ++++++++++++----------------------- src/lxc/conf.h | 5 +- src/lxc/confile.c | 16 +-- src/lxc/lsm/apparmor.c | 2 +- src/lxc/lxccontainer.c | 16 +-- src/lxc/start.c | 14 +- src/lxc/storage/overlay.c | 8 +- src/lxc/terminal.c | 2 +- 10 files changed, 116 insertions(+), 218 deletions(-) diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c index 23aef495c..e4d8243a1 100644 --- a/src/lxc/cgroups/cgfsng.c +++ b/src/lxc/cgroups/cgfsng.c @@ -575,7 +575,7 @@ __cgfsng_ops static void cgfsng_payload_destroy(struct cgroup_ops *ops, if (ret < 0) WARN("Failed to detach bpf program from cgroup"); - if (!lxc_list_empty(&handler->conf->id_map)) { + if (!list_empty(&handler->conf->id_map)) { struct generic_userns_exec_data wrap = { .conf = handler->conf, .path_prune = ops->container_limit_cgroup, @@ -1363,7 +1363,7 @@ __cgfsng_ops static bool cgfsng_chown(struct cgroup_ops *ops, if (!conf) return ret_set_errno(false, EINVAL); - if (lxc_list_empty(&conf->id_map)) + if (list_empty(&conf->id_map)) return true; wrap.origuid = geteuid(); @@ -2289,7 +2289,7 @@ static int __cg_unified_attach(const struct hierarchy *h, if (unified_fd < 0) return ret_errno(EBADF); - if (!lxc_list_empty(&conf->id_map)) { + if (!list_empty(&conf->id_map)) { struct userns_exec_unified_attach_data args = { .conf = conf, .unified_fd = unified_fd, @@ -3344,7 +3344,7 @@ static int initialize_cgroups(struct cgroup_ops *ops, struct lxc_conf *conf) */ ops->dfd_mnt = dfd; - ret = __initialize_cgroups(ops, conf->cgroup_meta.relative, !lxc_list_empty(&conf->id_map)); + ret = __initialize_cgroups(ops, conf->cgroup_meta.relative, !list_empty(&conf->id_map)); if (ret < 0) return syserror_ret(ret, "Failed to initialize cgroups"); @@ -3421,7 +3421,7 @@ static int __unified_attach_fd(const struct lxc_conf *conf, int fd_unified, pid_ { int ret; - if (!lxc_list_empty(&conf->id_map)) { + if (!list_empty(&conf->id_map)) { struct userns_exec_unified_attach_data args = { .conf = conf, .unified_fd = fd_unified, diff --git a/src/lxc/cmd/lxc_usernsexec.c b/src/lxc/cmd/lxc_usernsexec.c index 26022c806..fb560bf71 100644 --- a/src/lxc/cmd/lxc_usernsexec.c +++ b/src/lxc/cmd/lxc_usernsexec.c @@ -114,11 +114,10 @@ static int do_child(void *vargv) return -1; } -static struct lxc_list active_map; +static LIST_HEAD(active_map); static int add_map_entry(long host_id, long ns_id, long range, int which) { - struct lxc_list *tmp = NULL; struct id_map *newmap; newmap = malloc(sizeof(*newmap)); @@ -129,14 +128,8 @@ static int add_map_entry(long host_id, long ns_id, long range, int which) newmap->nsid = ns_id; newmap->range = range; newmap->idtype = which; - tmp = malloc(sizeof(*tmp)); - if (!tmp) { - free(newmap); - return -1; - } - tmp->elem = newmap; - lxc_list_add_tail(&active_map, tmp); + list_add_tail(&newmap->head, &active_map); return 0; } @@ -280,11 +273,9 @@ static bool do_map_self(void) { struct id_map *map; long nsuid = 0, nsgid = 0; - struct lxc_list *tmp = NULL; int ret; - lxc_list_for_each(tmp, &active_map) { - map = tmp->elem; + list_for_each_entry(map, &active_map, head) { if (map->idtype == ID_TYPE_UID) { if (is_in_ns_range(nsuid, map)) nsuid += map->range; @@ -336,8 +327,6 @@ int main(int argc, char *argv[]) } } - lxc_list_init(&active_map); - while ((c = getopt(argc, argv, "m:hs")) != EOF) { switch (c) { case 'm': @@ -359,7 +348,7 @@ int main(int argc, char *argv[]) } }; - if (lxc_list_empty(&active_map)) { + if (list_empty(&active_map)) { ret = find_default_map(); if (ret < 0) { fprintf(stderr, "Failed to find subuid or subgid allocation\n"); diff --git a/src/lxc/conf.c b/src/lxc/conf.c index f0c6c74be..11f42714b 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -619,7 +619,7 @@ int lxc_rootfs_prepare_parent(struct lxc_handler *handler) int ret; const char *path_source; - if (lxc_list_empty(&handler->conf->id_map)) + if (list_empty(&handler->conf->id_map)) return 0; if (is_empty_string(rootfs->mnt_opts.userns_path)) @@ -1616,7 +1616,6 @@ static const struct id_map *find_mapped_nsid_entry(const struct lxc_conf *conf, unsigned id, enum idtype idtype) { - struct lxc_list *it; struct id_map *map; struct id_map *retmap = NULL; @@ -1629,8 +1628,7 @@ static const struct id_map *find_mapped_nsid_entry(const struct lxc_conf *conf, return conf->root_nsgid_map; } - lxc_list_for_each(it, &conf->id_map) { - map = it->elem; + list_for_each_entry(map, &conf->id_map, head) { if (map->idtype != idtype) continue; @@ -3387,7 +3385,7 @@ struct lxc_conf *lxc_conf_init(void) lxc_list_init(&new->mount_list); lxc_list_init(&new->caps); lxc_list_init(&new->keepcaps); - lxc_list_init(&new->id_map); + INIT_LIST_HEAD(&new->id_map); new->root_nsuid_map = NULL; new->root_nsgid_map = NULL; lxc_list_init(&new->includes); @@ -3528,24 +3526,22 @@ static int lxc_map_ids_exec_wrapper(void *args) return -1; } -static struct id_map *find_mapped_hostid_entry(const struct lxc_list *idmap, +static struct id_map *find_mapped_hostid_entry(const struct list_head *idmap, unsigned id, enum idtype idtype); -int lxc_map_ids(struct lxc_list *idmap, pid_t pid) +int lxc_map_ids(struct list_head *idmap, pid_t pid) { - int fill, left; + int hostuid, hostgid, fill, left; char u_or_g; char *pos; char cmd_output[PATH_MAX]; struct id_map *map; - struct lxc_list *iterator; enum idtype type; int ret = 0, gidmap = 0, uidmap = 0; char mapbuf[STRLITERALLEN("new@idmap") + STRLITERALLEN(" ") + INTTYPE_TO_STRLEN(pid_t) + STRLITERALLEN(" ") + LXC_IDMAPLEN] = {0}; bool had_entry = false, maps_host_root = false, use_shadow = false; - int hostuid, hostgid; hostuid = geteuid(); hostgid = getegid(); @@ -3595,10 +3591,9 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid) /* Check if we really need to use newuidmap and newgidmap. * If the user is only remapping their own {g,u}id, we don't need it. */ - if (use_shadow && lxc_list_len(idmap) == 2) { + if (use_shadow && list_len(idmap) == 2) { use_shadow = false; - lxc_list_for_each(iterator, idmap) { - map = iterator->elem; + list_for_each_entry(map, idmap, head) { if (map->idtype == ID_TYPE_UID && map->range == 1 && map->nsid == hostuid && map->hostid == hostuid) continue; @@ -3617,8 +3612,7 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid) if (use_shadow) pos += sprintf(mapbuf, "new%cidmap %d", u_or_g, pid); - lxc_list_for_each(iterator, idmap) { - map = iterator->elem; + list_for_each_entry(map, idmap, head) { if (map->idtype != type) continue; @@ -3672,15 +3666,13 @@ static id_t get_mapped_rootid(const struct lxc_conf *conf, enum idtype idtype) { unsigned nsid; struct id_map *map; - struct lxc_list *it; if (idtype == ID_TYPE_UID) nsid = (conf->root_nsuid_map != NULL) ? 0 : conf->init_uid; else nsid = (conf->root_nsgid_map != NULL) ? 0 : conf->init_gid; - lxc_list_for_each (it, &conf->id_map) { - map = it->elem; + list_for_each_entry (map, &conf->id_map, head) { if (map->idtype != idtype) continue; if (map->nsid != nsid) @@ -3697,10 +3689,8 @@ static id_t get_mapped_rootid(const struct lxc_conf *conf, enum idtype idtype) int mapped_hostid(unsigned id, const struct lxc_conf *conf, enum idtype idtype) { struct id_map *map; - struct lxc_list *it; - lxc_list_for_each (it, &conf->id_map) { - map = it->elem; + list_for_each_entry(map, &conf->id_map, head) { if (map->idtype != idtype) continue; @@ -3714,12 +3704,10 @@ int mapped_hostid(unsigned id, const struct lxc_conf *conf, enum idtype idtype) int find_unmapped_nsid(const struct lxc_conf *conf, enum idtype idtype) { struct id_map *map; - struct lxc_list *it; unsigned int freeid = 0; again: - lxc_list_for_each (it, &conf->id_map) { - map = it->elem; + list_for_each_entry(map, &conf->id_map, head) { if (map->idtype != idtype) continue; @@ -4071,7 +4059,7 @@ static int lxc_rootfs_prepare_child(struct lxc_handler *handler) int dfd_idmapped = -EBADF; int ret; - if (lxc_list_empty(&handler->conf->id_map)) + if (list_empty(&handler->conf->id_map)) return 0; if (is_empty_string(rootfs->mnt_opts.userns_path)) @@ -4487,27 +4475,25 @@ int lxc_clear_config_caps(struct lxc_conf *c) return 0; } -static int lxc_free_idmap(struct lxc_list *id_map) +static int lxc_free_idmap(struct list_head *id_map) { - struct lxc_list *it, *next; + struct id_map *map, *nmap; - lxc_list_for_each_safe(it, id_map, next) { - lxc_list_del(it); - free(it->elem); - free(it); + list_for_each_entry_safe(map, nmap, id_map, head) { + list_del(&map->head); + free(map); } - lxc_list_init(id_map); + INIT_LIST_HEAD(id_map); return 0; } -static int __lxc_free_idmap(struct lxc_list *id_map) +static int __lxc_free_idmap(struct list_head *id_map) { lxc_free_idmap(id_map); - free(id_map); return 0; } -define_cleanup_function(struct lxc_list *, __lxc_free_idmap); +define_cleanup_function(struct list_head *, __lxc_free_idmap); int lxc_clear_idmaps(struct lxc_conf *c) { @@ -4905,15 +4891,13 @@ static struct id_map *mapped_nsid_add(const struct lxc_conf *conf, unsigned id, return retmap; } -static struct id_map *find_mapped_hostid_entry(const struct lxc_list *idmap, +static struct id_map *find_mapped_hostid_entry(const struct list_head *idmap, unsigned id, enum idtype idtype) { - struct id_map *map; - struct lxc_list *it; struct id_map *retmap = NULL; + struct id_map *map; - lxc_list_for_each (it, idmap) { - map = it->elem; + list_for_each_entry(map, idmap, head) { if (map->idtype != idtype) continue; @@ -4959,22 +4943,20 @@ static struct id_map *mapped_hostid_add(const struct lxc_conf *conf, uid_t id, return move_ptr(entry); } -static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf, - uid_t *resuid, gid_t *resgid) +static int get_minimal_idmap(const struct lxc_conf *conf, uid_t *resuid, + gid_t *resgid, struct list_head *head_ret) { __do_free struct id_map *container_root_uid = NULL, *container_root_gid = NULL, *host_uid_map = NULL, *host_gid_map = NULL; - __do_free struct lxc_list *idmap = NULL; uid_t euid, egid; uid_t nsuid = (conf->root_nsuid_map != NULL) ? 0 : conf->init_uid; gid_t nsgid = (conf->root_nsgid_map != NULL) ? 0 : conf->init_gid; - struct lxc_list *tmplist = NULL; /* Find container root mappings. */ container_root_uid = mapped_nsid_add(conf, nsuid, ID_TYPE_UID); if (!container_root_uid) - return log_debug(NULL, "Failed to find mapping for namespace uid %d", 0); + return sysdebug("Failed to find mapping for namespace uid %d", 0); euid = geteuid(); if (euid >= container_root_uid->hostid && euid < (container_root_uid->hostid + container_root_uid->range)) @@ -4982,7 +4964,7 @@ static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf, container_root_gid = mapped_nsid_add(conf, nsgid, ID_TYPE_GID); if (!container_root_gid) - return log_debug(NULL, "Failed to find mapping for namespace gid %d", 0); + return sysdebug("Failed to find mapping for namespace gid %d", 0); egid = getegid(); if (egid >= container_root_gid->hostid && egid < (container_root_gid->hostid + container_root_gid->range)) @@ -4992,50 +4974,31 @@ static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf, if (!host_uid_map) host_uid_map = mapped_hostid_add(conf, euid, ID_TYPE_UID); if (!host_uid_map) - return log_debug(NULL, "Failed to find mapping for uid %d", euid); + return sysdebug("Failed to find mapping for uid %d", euid); if (!host_gid_map) host_gid_map = mapped_hostid_add(conf, egid, ID_TYPE_GID); if (!host_gid_map) - return log_debug(NULL, "Failed to find mapping for gid %d", egid); + return sysdebug("Failed to find mapping for gid %d", egid); - /* Allocate new {g,u}id map list. */ - idmap = lxc_list_new(); - if (!idmap) - return NULL; - - /* Add container root to the map. */ - tmplist = lxc_list_new(); - if (!tmplist) - return NULL; /* idmap will now keep track of that memory. */ - lxc_list_add_elem(tmplist, move_ptr(host_uid_map)); - lxc_list_add_tail(idmap, tmplist); + list_add_tail(&host_uid_map->head, head_ret); + move_ptr(host_uid_map); if (container_root_uid) { - /* Add container root to the map. */ - tmplist = lxc_list_new(); - if (!tmplist) - return NULL; /* idmap will now keep track of that memory. */ - lxc_list_add_elem(tmplist, move_ptr(container_root_uid)); - lxc_list_add_tail(idmap, tmplist); + list_add_tail(&container_root_uid->head, head_ret); + move_ptr(container_root_uid); } - tmplist = lxc_list_new(); - if (!tmplist) - return NULL; /* idmap will now keep track of that memory. */ - lxc_list_add_elem(tmplist, move_ptr(host_gid_map)); - lxc_list_add_tail(idmap, tmplist); + list_add_tail(&host_gid_map->head, head_ret); + move_ptr(host_gid_map); if (container_root_gid) { - tmplist = lxc_list_new(); - if (!tmplist) - return NULL; /* idmap will now keep track of that memory. */ - lxc_list_add_elem(tmplist, move_ptr(container_root_gid)); - lxc_list_add_tail(idmap, tmplist); + list_add_tail(&container_root_gid->head, head_ret); + move_ptr(container_root_gid); } TRACE("Allocated minimal idmapping for ns uid %d and ns gid %d", nsuid, nsgid); @@ -5044,7 +5007,8 @@ static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf, *resuid = nsuid; if (resgid) *resgid = nsgid; - return move_ptr(idmap); + + return 0; } /* @@ -5062,7 +5026,8 @@ static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf, int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data, const char *fn_name) { - call_cleaner(__lxc_free_idmap) struct lxc_list *idmap = NULL; + LIST_HEAD(minimal_idmap); + call_cleaner(__lxc_free_idmap) struct list_head *idmap = &minimal_idmap; int ret = -1, status = -1; char c = '1'; struct userns_fn_data d = { @@ -5076,8 +5041,8 @@ int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data, if (!conf) return -EINVAL; - idmap = get_minimal_idmap(conf, NULL, NULL); - if (!idmap) + ret = get_minimal_idmap(conf, NULL, NULL, idmap); + if (ret) return ret_errno(ENOENT); ret = pipe2(pipe_fds, O_CLOEXEC); @@ -5098,13 +5063,10 @@ int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data, if (lxc_log_trace()) { struct id_map *map; - struct lxc_list *it; - lxc_list_for_each(it, idmap) { - map = it->elem; + list_for_each_entry(map, idmap, head) TRACE("Establishing %cid mapping for \"%d\" in new user namespace: nsuid %lu - hostid %lu - range %lu", (map->idtype == ID_TYPE_UID) ? 'u' : 'g', pid, map->nsid, map->hostid, map->range); - } } /* Set up {g,u}id mapping for user namespace of child process. */ @@ -5138,7 +5100,8 @@ int userns_exec_minimal(const struct lxc_conf *conf, int (*fn_parent)(void *), void *fn_parent_data, int (*fn_child)(void *), void *fn_child_data) { - call_cleaner(__lxc_free_idmap) struct lxc_list *idmap = NULL; + LIST_HEAD(minimal_idmap); + call_cleaner(__lxc_free_idmap) struct list_head *idmap = &minimal_idmap; uid_t resuid = LXC_INVALID_UID; gid_t resgid = LXC_INVALID_GID; char c = '1'; @@ -5149,8 +5112,8 @@ int userns_exec_minimal(const struct lxc_conf *conf, if (!conf || !fn_child) return ret_errno(EINVAL); - idmap = get_minimal_idmap(conf, &resuid, &resgid); - if (!idmap) + ret = get_minimal_idmap(conf, &resuid, &resgid, idmap); + if (ret) return ret_errno(ENOENT); ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sock_fds); @@ -5212,13 +5175,10 @@ int userns_exec_minimal(const struct lxc_conf *conf, if (lxc_log_trace()) { struct id_map *map; - struct lxc_list *it; - lxc_list_for_each(it, idmap) { - map = it->elem; + list_for_each_entry(map, idmap, head) TRACE("Establishing %cid mapping for \"%d\" in new user namespace: nsuid %lu - hostid %lu - range %lu", (map->idtype == ID_TYPE_UID) ? 'u' : 'g', pid, map->nsid, map->hostid, map->range); - } } ret = lxc_read_nointr(sock_fds[1], &c, 1); @@ -5260,26 +5220,24 @@ on_error: int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data, const char *fn_name) { + LIST_HEAD(full_idmap); + int ret = -1; + char c = '1'; + struct id_map *container_root_uid = NULL, *container_root_gid = NULL, + *host_uid_map = NULL, *host_gid_map = NULL; pid_t pid; uid_t euid, egid; int p[2]; struct id_map *map; - struct lxc_list *cur; struct userns_fn_data d; - int ret = -1; - char c = '1'; - struct lxc_list *idmap = NULL, *tmplist = NULL; - struct id_map *container_root_uid = NULL, *container_root_gid = NULL, - *host_uid_map = NULL, *host_gid_map = NULL; if (!conf) return -EINVAL; ret = pipe2(p, O_CLOEXEC); - if (ret < 0) { - SYSERROR("opening pipe"); - return -1; - } + if (ret < 0) + return -errno; + d.fn = fn; d.fn_name = fn_name; d.arg = data; @@ -5299,32 +5257,16 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data, euid = geteuid(); egid = getegid(); - /* Allocate new {g,u}id map list. */ - idmap = lxc_list_new(); - if (!idmap) - goto on_error; - /* Find container root. */ - lxc_list_for_each (cur, &conf->id_map) { - struct id_map *tmpmap; + list_for_each_entry(map, &conf->id_map, head) { + __do_free struct id_map *dup_map = NULL; - tmplist = lxc_list_new(); - if (!tmplist) + dup_map = memdup(map, sizeof(struct id_map)); + if (!dup_map) goto on_error; - tmpmap = zalloc(sizeof(*tmpmap)); - if (!tmpmap) { - free(tmplist); - goto on_error; - } - - memset(tmpmap, 0, sizeof(*tmpmap)); - memcpy(tmpmap, cur->elem, sizeof(*tmpmap)); - tmplist->elem = tmpmap; - - lxc_list_add_tail(idmap, tmplist); - - map = cur->elem; + list_add_tail(&dup_map->head, &full_idmap); + move_ptr(dup_map); if (map->idtype == ID_TYPE_UID) if (euid >= map->hostid && euid < map->hostid + map->range) @@ -5373,39 +5315,27 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data, } if (host_uid_map && (host_uid_map != container_root_uid)) { - /* Add container root to the map. */ - tmplist = lxc_list_new(); - if (!tmplist) - goto on_error; - lxc_list_add_elem(tmplist, host_uid_map); - lxc_list_add_tail(idmap, tmplist); + /* idmap will now keep track of that memory. */ + list_add_tail(&host_uid_map->head, &full_idmap); + move_ptr(host_uid_map); } - /* idmap will now keep track of that memory. */ - host_uid_map = NULL; if (host_gid_map && (host_gid_map != container_root_gid)) { - tmplist = lxc_list_new(); - if (!tmplist) - goto on_error; - lxc_list_add_elem(tmplist, host_gid_map); - lxc_list_add_tail(idmap, tmplist); + /* idmap will now keep track of that memory. */ + list_add_tail(&host_gid_map->head, &full_idmap); + move_ptr(host_gid_map); } - /* idmap will now keep track of that memory. */ - host_gid_map = NULL; if (lxc_log_trace()) { - lxc_list_for_each (cur, idmap) { - map = cur->elem; - TRACE("establishing %cid mapping for \"%d\" in new " - "user namespace: nsuid %lu - hostid %lu - range " - "%lu", + list_for_each_entry(map, &full_idmap, head) { + TRACE("establishing %cid mapping for \"%d\" in new user namespace: nsuid %lu - hostid %lu - range %lu", (map->idtype == ID_TYPE_UID) ? 'u' : 'g', pid, map->nsid, map->hostid, map->range); } } /* Set up {g,u}id mapping for user namespace of child process. */ - ret = lxc_map_ids(idmap, pid); + ret = lxc_map_ids(&full_idmap, pid); if (ret < 0) { ERROR("error setting up {g,u}id mappings for child process \"%d\"", pid); goto on_error; @@ -5426,8 +5356,7 @@ on_error: if (pid > 0) ret = wait_for_pid(pid); - if (idmap) - __lxc_free_idmap(idmap); + __lxc_free_idmap(&full_idmap); if (host_uid_map && (host_uid_map != container_root_uid)) free(host_uid_map); @@ -5437,12 +5366,11 @@ on_error: return ret; } -static int add_idmap_entry(struct lxc_list *idmap, enum idtype idtype, +static int add_idmap_entry(struct list_head *idmap_list, enum idtype idtype, unsigned long nsid, unsigned long hostid, unsigned long range) { __do_free struct id_map *new_idmap = NULL; - __do_free struct lxc_list *new_list = NULL; new_idmap = zalloc(sizeof(*new_idmap)); if (!new_idmap) @@ -5453,12 +5381,8 @@ static int add_idmap_entry(struct lxc_list *idmap, enum idtype idtype, new_idmap->nsid = nsid; new_idmap->range = range; - new_list = zalloc(sizeof(*new_list)); - if (!new_list) - return ret_errno(ENOMEM); - - new_list->elem = move_ptr(new_idmap); - lxc_list_add_tail(idmap, move_ptr(new_list)); + list_add_tail(&new_idmap->head, idmap_list); + move_ptr(new_idmap); INFO("Adding id map: type %c nsid %lu hostid %lu range %lu", idtype == ID_TYPE_UID ? 'u' : 'g', nsid, hostid, range); @@ -5468,7 +5392,8 @@ static int add_idmap_entry(struct lxc_list *idmap, enum idtype idtype, int userns_exec_mapped_root(const char *path, int path_fd, const struct lxc_conf *conf) { - call_cleaner(__lxc_free_idmap) struct lxc_list *idmap = NULL; + LIST_HEAD(idmap_list); + call_cleaner(__lxc_free_idmap) struct list_head *idmap = &idmap_list; __do_close int fd = -EBADF; int target_fd = -EBADF; char c = '1'; @@ -5534,10 +5459,6 @@ int userns_exec_mapped_root(const char *path, int path_fd, TRACE("Chowned %d(%s) to -1:%d", target_fd, path, hostgid); } - idmap = lxc_list_new(); - if (!idmap) - return -ENOMEM; - /* "u:0:rootuid:1" */ ret = add_idmap_entry(idmap, ID_TYPE_UID, 0, container_host_uid, 1); if (ret < 0) @@ -5615,13 +5536,10 @@ int userns_exec_mapped_root(const char *path, int path_fd, if (lxc_log_trace()) { struct id_map *map; - struct lxc_list *it; - lxc_list_for_each(it, idmap) { - map = it->elem; + list_for_each_entry(map, idmap, head) TRACE("Establishing %cid mapping for \"%d\" in new user namespace: nsuid %lu - hostid %lu - range %lu", (map->idtype == ID_TYPE_UID) ? 'u' : 'g', pid, map->nsid, map->hostid, map->range); - } } ret = lxc_read_nointr(sock_fds[1], &c, 1); diff --git a/src/lxc/conf.h b/src/lxc/conf.h index e8d776cdc..5965e9e3d 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -181,6 +181,7 @@ define_cleanup_function(struct lxc_proc *, free_lxc_proc); struct id_map { enum idtype idtype; unsigned long hostid, nsid, range; + struct list_head head; }; /* Defines the number of tty configured and contains the @@ -352,7 +353,7 @@ struct lxc_conf { }; struct { - struct lxc_list id_map; + struct list_head id_map; /* * Pointer to the idmap entry for the container's root uid in @@ -525,7 +526,7 @@ __hidden extern void lxc_storage_put(struct lxc_conf *conf); __hidden extern int lxc_rootfs_init(struct lxc_conf *conf, bool userns); __hidden extern int lxc_rootfs_prepare_parent(struct lxc_handler *handler); __hidden extern int lxc_idmapped_mounts_parent(struct lxc_handler *handler); -__hidden extern int lxc_map_ids(struct lxc_list *idmap, pid_t pid); +__hidden extern int lxc_map_ids(struct list_head *idmap, pid_t pid); __hidden extern int lxc_create_tty(const char *name, struct lxc_conf *conf); __hidden extern void lxc_delete_tty(struct lxc_tty_info *ttys); __hidden extern int lxc_clear_config_caps(struct lxc_conf *c); diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 513b917d9..d9d3e45df 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -2210,7 +2210,6 @@ static int set_config_proc(const char *key, const char *value, static int set_config_idmaps(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { - __do_free struct lxc_list *idmaplist = NULL; __do_free struct id_map *idmap = NULL; unsigned long hostid, nsid, range; char type; @@ -2219,10 +2218,6 @@ static int set_config_idmaps(const char *key, const char *value, if (lxc_config_value_empty(value)) return lxc_clear_idmaps(lxc_conf); - idmaplist = lxc_list_new(); - if (!idmaplist) - return ret_errno(ENOMEM); - idmap = zalloc(sizeof(*idmap)); if (!idmap) return ret_errno(ENOMEM); @@ -2242,8 +2237,7 @@ static int set_config_idmaps(const char *key, const char *value, idmap->hostid = hostid; idmap->nsid = nsid; idmap->range = range; - idmaplist->elem = idmap; - lxc_list_add_tail(&lxc_conf->id_map, idmaplist); + list_add_tail(&idmap->head, &lxc_conf->id_map); if (!lxc_conf->root_nsuid_map && idmap->idtype == ID_TYPE_UID) if (idmap->nsid == 0) @@ -2254,7 +2248,6 @@ static int set_config_idmaps(const char *key, const char *value, lxc_conf->root_nsgid_map = idmap; move_ptr(idmap); - move_ptr(idmaplist); return 0; } @@ -3996,7 +3989,7 @@ static inline int get_config_cgroup_relative(const char *key, char *retv, static int get_config_idmaps(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { - struct lxc_list *it; + struct id_map *map; int len, listlen, ret; int fulllen = 0; /* "u 1000 1000000 65536" @@ -4027,9 +4020,8 @@ static int get_config_idmaps(const char *key, char *retv, int inlen, else memset(retv, 0, inlen); - listlen = lxc_list_len(&c->id_map); - lxc_list_for_each(it, &c->id_map) { - struct id_map *map = it->elem; + listlen = list_len(&c->id_map); + list_for_each_entry(map, &c->id_map, head) { ret = strnprintf(buf, sizeof(buf), "%c %lu %lu %lu", (map->idtype == ID_TYPE_UID) ? 'u' : 'g', map->nsid, map->hostid, map->range); diff --git a/src/lxc/lsm/apparmor.c b/src/lxc/lsm/apparmor.c index a0d81ea01..63d122591 100644 --- a/src/lxc/lsm/apparmor.c +++ b/src/lxc/lsm/apparmor.c @@ -668,7 +668,7 @@ static void must_append_sized(char **buf, size_t *bufsz, const char *data, size_ static bool is_privileged(struct lxc_conf *conf) { - return lxc_list_empty(&conf->id_map); + return list_empty(&conf->id_map); } static const char* AA_ALL_DEST_PATH_LIST[] = { diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 96c3ee31b..fea073f14 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -1219,7 +1219,7 @@ static int do_create_container_dir(const char *path, struct lxc_conf *conf) ret = 0; } - if (!lxc_list_empty(&conf->id_map)) { + if (!list_empty(&conf->id_map)) { ret = chown_mapped_root(path, conf); if (ret < 0) ret = -1; @@ -1290,7 +1290,7 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c, /* If we are not root, chown the rootfs dir to root in the target user * namespace. */ - if (am_guest_unpriv() || !lxc_list_empty(&c->lxc_conf->id_map)) { + if (am_guest_unpriv() || !list_empty(&c->lxc_conf->id_map)) { ret = chown_mapped_root(bdev->dest, c->lxc_conf); if (ret < 0) { ERROR("Error chowning \"%s\" to container root", bdev->dest); @@ -1482,11 +1482,10 @@ static bool create_run_template(struct lxc_container *c, char *tpath, * ... <-m mapn> -- and we append "--mapped-uid x", where x is * the mapped uid for our geteuid() */ - if (!lxc_list_empty(&conf->id_map)) { + if (!list_empty(&conf->id_map)) { int extraargs, hostuid_mapped, hostgid_mapped; char **n2; char txtuid[20], txtgid[20]; - struct lxc_list *it; struct id_map *map; int n2args = 1; @@ -1498,8 +1497,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, tpath = "lxc-usernsexec"; n2[0] = "lxc-usernsexec"; - lxc_list_for_each(it, &conf->id_map) { - map = it->elem; + list_for_each_entry(map, &conf->id_map, head) { n2args += 2; n2 = realloc(n2, n2args * sizeof(char *)); if (!n2) @@ -2239,7 +2237,7 @@ static inline bool enter_net_ns(struct lxc_container *c) if (pid < 0) return false; - if ((geteuid() != 0 || (c->lxc_conf && !lxc_list_empty(&c->lxc_conf->id_map))) && + if ((geteuid() != 0 || (c->lxc_conf && !list_empty(&c->lxc_conf->id_map))) && (access("/proc/self/ns/user", F_OK) == 0)) if (!switch_to_ns(pid, "user")) return false; @@ -5077,7 +5075,7 @@ static int do_lxcapi_mount(struct lxc_container *c, const char *source, } /* Enter the container namespaces */ - if (!lxc_list_empty(&c->lxc_conf->id_map)) { + if (!list_empty(&c->lxc_conf->id_map)) { if (!switch_to_ns(init_pid, "user")) { ERROR("Failed to enter user namespace"); _exit(EXIT_FAILURE); @@ -5170,7 +5168,7 @@ static int do_lxcapi_umount(struct lxc_container *c, const char *target, } /* Enter the container namespaces */ - if (!lxc_list_empty(&c->lxc_conf->id_map)) { + if (!list_empty(&c->lxc_conf->id_map)) { if (!switch_to_ns(init_pid, "user")) { ERROR("Failed to enter user namespace"); _exit(EXIT_FAILURE); diff --git a/src/lxc/start.c b/src/lxc/start.c index 4f09e4e5c..7041a913c 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1110,7 +1110,7 @@ static int do_start(void *data) /* If we are in a new user namespace, become root there to have * privilege over our namespace. */ - if (!lxc_list_empty(&handler->conf->id_map)) { + if (!list_empty(&handler->conf->id_map)) { if (!handler->conf->root_nsuid_map) nsuid = handler->conf->init_uid; @@ -1406,7 +1406,7 @@ static int do_start(void *data) * we switched to root in the new user namespace further above. Only * drop groups if we can, so ensure that we have necessary privilege. */ - if (lxc_list_empty(&handler->conf->id_map)) { + if (list_empty(&handler->conf->id_map)) { #if HAVE_LIBCAP if (lxc_proc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE)) #endif @@ -1473,7 +1473,7 @@ int resolve_clone_flags(struct lxc_handler *handler) if ((conf->ns_clone & ns_info[i].clone_flag)) handler->ns_clone_flags |= ns_info[i].clone_flag; } else { - if (i == LXC_NS_USER && lxc_list_empty(&handler->conf->id_map)) + if (i == LXC_NS_USER && list_empty(&handler->conf->id_map)) continue; if (i == LXC_NS_NET && lxc_requests_empty_network(handler)) @@ -1576,7 +1576,7 @@ static int lxc_spawn(struct lxc_handler *handler) int i, ret; char pidstr[20]; bool wants_to_map_ids; - struct lxc_list *id_map; + struct list_head *id_map; const char *name = handler->name; const char *lxcpath = handler->lxcpath; bool share_ns = false; @@ -1584,7 +1584,7 @@ static int lxc_spawn(struct lxc_handler *handler) struct cgroup_ops *cgroup_ops = handler->cgroup_ops; id_map = &conf->id_map; - wants_to_map_ids = !lxc_list_empty(id_map); + wants_to_map_ids = !list_empty(id_map); for (i = 0; i < LXC_NS_MAX; i++) { if (!conf->ns_share[i]) @@ -2012,14 +2012,14 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, * it readonly. * If the container is unprivileged then skip rootfs pinning. */ - ret = lxc_rootfs_init(conf, !lxc_list_empty(&conf->id_map)); + ret = lxc_rootfs_init(conf, !list_empty(&conf->id_map)); if (ret) { ERROR("Failed to handle rootfs pinning for container \"%s\"", handler->name); ret = -1; goto out_abort; } - if (geteuid() == 0 && !lxc_list_empty(&conf->id_map)) { + if (geteuid() == 0 && !list_empty(&conf->id_map)) { /* * Most filesystems can't be mounted inside a userns so handle them here. */ diff --git a/src/lxc/storage/overlay.c b/src/lxc/storage/overlay.c index 8fe523973..1479a9ce8 100644 --- a/src/lxc/storage/overlay.c +++ b/src/lxc/storage/overlay.c @@ -57,7 +57,7 @@ int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char return -1; } - if (am_guest_unpriv() || !lxc_list_empty(&conf->id_map)) { + if (am_guest_unpriv() || !list_empty(&conf->id_map)) { ret = chown_mapped_root(new->dest, conf); if (ret < 0) WARN("Failed to update ownership of %s", new->dest); @@ -88,7 +88,7 @@ int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char if (ret < 0 && errno != EEXIST) return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", work); - if (am_guest_unpriv() || !lxc_list_empty(&conf->id_map)) { + if (am_guest_unpriv() || !list_empty(&conf->id_map)) { __do_free char *lxc_overlay_delta_dir = NULL, *lxc_overlay_private_dir = NULL; @@ -155,7 +155,7 @@ int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char if (ret < 0 && errno != EEXIST) return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", ndelta); - if (am_guest_unpriv() || !lxc_list_empty(&conf->id_map)) { + if (am_guest_unpriv() || !list_empty(&conf->id_map)) { __do_free char *lxc_overlay_delta_dir = NULL, *lxc_overlay_private_dir = NULL; @@ -276,7 +276,7 @@ int ovl_create(struct lxc_storage *bdev, const char *dest, const char *n, if (ret < 0 && errno != EEXIST) return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", delta); - if (am_guest_unpriv() || !lxc_list_empty(&conf->id_map)) { + if (am_guest_unpriv() || !list_empty(&conf->id_map)) { __do_free char *lxc_overlay_private_dir = NULL; lxc_overlay_private_dir = must_make_path(tmp, LXC_OVERLAY_PRIVATE_DIR, NULL); diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c index da5748748..7327893b3 100644 --- a/src/lxc/terminal.c +++ b/src/lxc/terminal.c @@ -876,7 +876,7 @@ static int lxc_terminal_map_ids(struct lxc_conf *c, struct lxc_terminal *termina { int ret; - if (lxc_list_empty(&c->id_map)) + if (list_empty(&c->id_map)) return 0; if (is_empty_string(terminal->name) && terminal->pty < 0) From 091f611c7ca02d935bf32771bb73e262c9881638 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 26 Aug 2021 10:17:21 +0200 Subject: [PATCH 06/15] conf: remove unused mountflags nember Signed-off-by: Christian Brauner --- src/lxc/conf.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 5965e9e3d..7a63acffc 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -246,7 +246,6 @@ struct lxc_rootfs { char buf[PATH_MAX]; char *bdev_type; char *options; - unsigned long mountflags; bool managed; struct lxc_mount_options mnt_opts; struct lxc_storage *storage; From e73af35bbac645b4d1b8d5f5037863a1d49b6cce Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 26 Aug 2021 10:25:48 +0200 Subject: [PATCH 07/15] rootfs: remove "options" member Signed-off-by: Christian Brauner --- src/lxc/conf.c | 7 +++---- src/lxc/conf.h | 4 ++-- src/lxc/confile.c | 5 ++--- src/lxc/storage/storage.c | 2 +- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 11f42714b..4b7a73286 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -512,7 +512,7 @@ int lxc_storage_prepare(struct lxc_conf *conf) if (!rootfs->storage) return log_error(-1, "Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"", rootfs->path, rootfs->mount, - rootfs->options ? rootfs->options : "(null)"); + rootfs->mnt_opts.raw_options ? rootfs->mnt_opts.raw_options : "(null)"); return 0; } @@ -1425,11 +1425,11 @@ static int lxc_mount_rootfs(struct lxc_rootfs *rootfs) if (ret < 0) return log_error(-1, "Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"", rootfs->path, rootfs->mount, - rootfs->options ? rootfs->options : "(null)"); + rootfs->mnt_opts.raw_options ? rootfs->mnt_opts.raw_options : "(null)"); DEBUG("Mounted rootfs \"%s\" onto \"%s\" with options \"%s\"", rootfs->path, rootfs->mount, - rootfs->options ? rootfs->options : "(null)"); + rootfs->mnt_opts.raw_options ? rootfs->mnt_opts.raw_options : "(null)"); rootfs->dfd_mnt = open_at(-EBADF, rootfs->mount, PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_ABSOLUTE_XDEV, 0); if (rootfs->dfd_mnt < 0) @@ -4791,7 +4791,6 @@ void lxc_conf_free(struct lxc_conf *conf) lxc_terminal_conf_free(&conf->console); free(conf->rootfs.mount); free(conf->rootfs.bdev_type); - free(conf->rootfs.options); free(conf->rootfs.path); put_lxc_rootfs(&conf->rootfs, true); free(conf->logfile); diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 7a63acffc..4e31c55d7 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -218,6 +218,7 @@ struct lxc_mount_options { unsigned long prop_flags; char *data; struct lxc_mount_attr attr; + char *raw_options; }; /* Defines a structure to store the rootfs location, the @@ -226,7 +227,6 @@ struct lxc_mount_options { * @mount : where it is mounted * @buf : static buffer to construct paths * @bev_type : optional backing store type - * @options : mount options * @managed : whether it is managed by LXC * @dfd_mnt : fd for @mount * @dfd_dev : fd for /dev of the container @@ -245,7 +245,6 @@ struct lxc_rootfs { char buf[PATH_MAX]; char *bdev_type; - char *options; bool managed; struct lxc_mount_options mnt_opts; struct lxc_storage *storage; @@ -613,6 +612,7 @@ static inline void put_lxc_mount_options(struct lxc_mount_options *mnt_opts) mnt_opts->prop_flags = 0; free_disarm(mnt_opts->data); + free_disarm(mnt_opts->raw_options); } static inline void put_lxc_rootfs(struct lxc_rootfs *rootfs, bool unpin) diff --git a/src/lxc/confile.c b/src/lxc/confile.c index d9d3e45df..d0b891d2d 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -2784,7 +2784,7 @@ static int set_config_rootfs_options(const char *key, const char *value, if (ret < 0) return ret_errno(EINVAL); - rootfs->options = move_ptr(raw_options); + rootfs->mnt_opts.raw_options = move_ptr(raw_options); return 0; } @@ -4169,7 +4169,7 @@ static int get_config_rootfs_mount(const char *key, char *retv, int inlen, static int get_config_rootfs_options(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { - return lxc_get_conf_str(retv, inlen, c->rootfs.options); + return lxc_get_conf_str(retv, inlen, c->rootfs.mnt_opts.raw_options); } static int get_config_uts_name(const char *key, char *retv, int inlen, @@ -4976,7 +4976,6 @@ static inline int clr_config_rootfs_mount(const char *key, struct lxc_conf *c, static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c, void *data) { - free_disarm(c->rootfs.options); put_lxc_mount_options(&c->rootfs.mnt_opts); return 0; diff --git a/src/lxc/storage/storage.c b/src/lxc/storage/storage.c index f1bea3e30..a8c4be5f3 100644 --- a/src/lxc/storage/storage.c +++ b/src/lxc/storage/storage.c @@ -606,7 +606,7 @@ struct lxc_storage *storage_init(struct lxc_conf *conf) const struct lxc_storage_type *q; const char *src = conf->rootfs.path; const char *dst = conf->rootfs.mount; - const char *mntopts = conf->rootfs.options; + const char *mntopts = conf->rootfs.mnt_opts.raw_options; BUILD_BUG_ON(LXC_STORAGE_INTERNAL_OVERLAY_RESTORE <= LXC_CLONE_MAXFLAGS); From 3eb2323041e757a1b83efa131061b96426f2fd7d Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 26 Aug 2021 10:47:47 +0200 Subject: [PATCH 08/15] conf: rework recursive mount option handling Signed-off-by: Christian Brauner --- src/lxc/conf.c | 30 +++++++++++++++--------------- src/lxc/conf.h | 3 ++- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 4b7a73286..0a01916c3 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -2237,7 +2237,7 @@ static int parse_vfs_attr(struct lxc_mount_options *opts, char *opt, size_t size /* This is a recursive bind-mount. */ if (strequal(mo->name, "rbind")) { - opts->recursive = 1; + opts->bind_recursively = 1; opts->bind = 1; opts->mnt_flags |= mo->legacy_flag; /* MS_BIND | MS_REC */ return 0; @@ -2933,10 +2933,10 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f) dfd_from = rootfs->dfd_host; fd_from = open_tree(dfd_from, source_relative, OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC | - (opts.recursive ? AT_RECURSIVE : 0)); + (opts.bind_recursively ? AT_RECURSIVE : 0)); if (fd_from < 0) return syserror("Failed to create detached %smount of %d/%s", - opts.recursive ? "recursive " : "", + opts.bind_recursively ? "recursive " : "", dfd_from, source_relative); if (strequal(opts.userns_path, "container")) @@ -2951,7 +2951,7 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f) } return syserror("Failed to open user namespace \"%s\" for detached %smount of %d/%s", - opts.userns_path, opts.recursive ? "recursive " : "", + opts.userns_path, opts.bind_recursively ? "recursive " : "", dfd_from, source_relative); } @@ -2965,7 +2965,7 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f) } return syserror("Failed to send file descriptor %d for detached %smount of %d/%s and file descriptor %d of user namespace \"%s\" to parent", - fd_from, opts.recursive ? "recursive " : "", + fd_from, opts.bind_recursively ? "recursive " : "", dfd_from, source_relative, fd_userns, opts.userns_path); } @@ -2980,7 +2980,7 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f) } return syserror("Failed to receive notification that parent idmapped detached %smount %d/%s to user namespace %d", - opts.recursive ? "recursive " : "", + opts.bind_recursively ? "recursive " : "", dfd_from, source_relative, fd_userns); } @@ -2991,7 +2991,7 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f) /* Set remaining mount options. */ ret = mount_setattr(fd_from, "", AT_EMPTY_PATH | - (opts.recursive ? AT_RECURSIVE : 0), + (opts.bind_recursively ? AT_RECURSIVE : 0), &opts.attr, sizeof(opts.attr)); if (ret < 0) { if (opts.optional) { @@ -3000,7 +3000,7 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f) } return syserror("Failed to receive notification that parent idmapped detached %smount %d/%s to user namespace %d", - opts.recursive ? "recursive " : "", + opts.bind_recursively ? "recursive " : "", dfd_from, source_relative, fd_userns); } @@ -3025,7 +3025,7 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f) return syserror("Failed to open target mountpoint %d/%s for detached idmapped %smount %d:%d/%s", dfd_from, target_relative, - opts.recursive ? "recursive " : "", + opts.bind_recursively ? "recursive " : "", fd_userns, dfd_from, source_relative); } @@ -3037,12 +3037,12 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f) } return syserror("Failed to attach detached idmapped %smount %d:%d/%s to target mountpoint %d/%s", - opts.recursive ? "recursive " : "", + opts.bind_recursively ? "recursive " : "", fd_userns, dfd_from, source_relative, dfd_from, target_relative); } TRACE("Attached detached idmapped %smount %d:%d/%s to target mountpoint %d/%s", - opts.recursive ? "recursive " : "", fd_userns, dfd_from, + opts.bind_recursively ? "recursive " : "", fd_userns, dfd_from, source_relative, dfd_from, target_relative); } @@ -4100,11 +4100,11 @@ int lxc_idmapped_mounts_parent(struct lxc_handler *handler) attr.userns_fd = fd_userns; ret = mount_setattr(fd_from, "", AT_EMPTY_PATH | - (opts.recursive ? AT_RECURSIVE : 0), + (opts.bind_recursively ? AT_RECURSIVE : 0), &attr, sizeof(attr)); if (ret) return syserror("Failed to idmap detached %smount %d to %d", - opts.recursive ? "recursive " : "", + opts.bind_recursively ? "recursive " : "", fd_from, fd_userns); ret = lxc_abstract_unix_send_credential(handler->data_sock[1], @@ -4112,11 +4112,11 @@ int lxc_idmapped_mounts_parent(struct lxc_handler *handler) sizeof(mnt_seq)); if (ret < 0) return syserror("Parent failed to notify child that detached %smount %d was idmapped to user namespace %d", - opts.recursive ? "recursive " : "", + opts.bind_recursively ? "recursive " : "", fd_from, fd_userns); TRACE("Parent idmapped detached %smount %d to user namespace %d", - opts.recursive ? "recursive " : "", fd_from, fd_userns); + opts.bind_recursively ? "recursive " : "", fd_from, fd_userns); mnt_seq++; } } diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 4e31c55d7..0843c99ad 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -211,7 +211,8 @@ struct lxc_mount_options { unsigned int create_file : 1; unsigned int optional : 1; unsigned int relative : 1; - unsigned int recursive : 1; + unsigned int bind_recursively : 1; + unsigned int propagate_recursively : 1; unsigned int bind : 1; char userns_path[PATH_MAX]; unsigned long mnt_flags; From 6b48a57529f4c5ee100898e4ef08220c56e90634 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 26 Aug 2021 11:06:52 +0200 Subject: [PATCH 09/15] conf: support recursive propagation options properly Signed-off-by: Christian Brauner --- src/lxc/conf.c | 50 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 0a01916c3..8d0cd5f40 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -2270,9 +2270,14 @@ static int parse_vfs_attr(struct lxc_mount_options *opts, char *opt, size_t size if (!strnequal(opt, mo->name, strlen(mo->name))) continue; - /* TODO: Handle recursive propagation requests. */ + if (strequal(mo->name, "rslave") || + strequal(mo->name, "rshared") || + strequal(mo->name, "runbindable") || + strequal(mo->name, "rprivate")) + opts->propagate_recursively = 1; + opts->attr.propagation = mo->flag; - opts->mnt_flags |= mo->legacy_flag; + opts->prop_flags |= mo->legacy_flag; return 0; } @@ -2892,6 +2897,7 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f) struct lxc_mount_options opts = {}; int dfd_from; const char *source_relative, *target_relative; + struct lxc_mount_attr attr = {}; ret = parse_lxc_mount_attrs(&opts, mntent.mnt_opts); if (ret < 0) @@ -2989,21 +2995,51 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f) mnt_seq, cur_mnt_seq); mnt_seq++; - /* Set remaining mount options. */ - ret = mount_setattr(fd_from, "", AT_EMPTY_PATH | + /* Set regular mount options. */ + attr = opts.attr; + attr.propagation = 0; + ret = mount_setattr(fd_from, + "", + AT_EMPTY_PATH | (opts.bind_recursively ? AT_RECURSIVE : 0), - &opts.attr, sizeof(opts.attr)); + &attr, + sizeof(attr)); if (ret < 0) { if (opts.optional) { TRACE("Skipping optional idmapped mount"); continue; } - return syserror("Failed to receive notification that parent idmapped detached %smount %d/%s to user namespace %d", + return syserror("Failed to set %smount options on detached %d/%s", opts.bind_recursively ? "recursive " : "", - dfd_from, source_relative, fd_userns); + dfd_from, source_relative); } + /* Set propagation mount options. */ + if (opts.attr.propagation) { + attr = (struct lxc_mount_attr) { + attr.propagation = opts.attr.propagation, + }; + + ret = mount_setattr(fd_from, + "", + AT_EMPTY_PATH | + (opts.propagate_recursively ? AT_RECURSIVE : 0), + &attr, + sizeof(attr)); + if (ret < 0) { + if (opts.optional) { + TRACE("Skipping optional idmapped mount"); + continue; + } + + return syserror("Failed to set %spropagation mount options on detached %d/%s", + opts.bind_recursively ? "recursive " : "", + dfd_from, source_relative); + } + } + + /* * In contrast to the legacy mount codepath we will simplify * our lifes and just always treat the target mountpoint to be From 2ff1170b42ef66b38988a513e223dc3756ebc5e5 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 26 Aug 2021 11:11:08 +0200 Subject: [PATCH 10/15] conf: switch to parse_mount_attrs() even for legacy mount() Signed-off-by: Christian Brauner --- src/lxc/conf.c | 56 ++++++++++---------------------------------------- 1 file changed, 11 insertions(+), 45 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 8d0cd5f40..12fc7fa26 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -2331,43 +2331,6 @@ int parse_mount_attrs(struct lxc_mount_options *opts, const char *mntopts) return 0; } -static void parse_propagationopt(char *opt, unsigned long *flags) -{ - struct mount_opt *mo; - - /* If opt is found in propagation_opt, set or clear flags. */ - for (mo = &propagation_opt[0]; mo->name != NULL; mo++) { - if (!strnequal(opt, mo->name, strlen(mo->name))) - continue; - - if (mo->clear) - *flags &= ~mo->legacy_flag; - else - *flags |= mo->legacy_flag; - - return; - } -} - -int parse_propagationopts(const char *mntopts, unsigned long *pflags) -{ - __do_free char *s = NULL; - char *p; - - if (!mntopts) - return 0; - - s = strdup(mntopts); - if (!s) - return log_error_errno(-ENOMEM, errno, "Failed to allocate memory"); - - *pflags = 0L; - lxc_iterate_parts(p, s, ",") - parse_propagationopt(p, pflags); - - return 0; -} - static void null_endofword(char *word) { while (*word && *word != ' ' && *word != '\t') @@ -2619,7 +2582,6 @@ static inline int mount_entry_on_generic(struct mntent *mntent, const char *lxc_path) { __do_free char *mntdata = NULL; - unsigned long mntflags = 0, pflags = 0; char *rootfs_path = NULL; int ret; bool dev, optional, relative; @@ -2655,16 +2617,20 @@ static inline int mount_entry_on_generic(struct mntent *mntent, if (!is_empty_string(opts.userns_path)) return systrace_ret(0, "Skipping idmapped mount entry"); - ret = parse_propagationopts(mntent->mnt_opts, &pflags); + ret = parse_mount_attrs(&opts, mntent->mnt_opts); if (ret < 0) return -1; - ret = parse_mntopts_legacy(mntent->mnt_opts, &mntflags, &mntdata); - if (ret < 0) - return ret; - - ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, mntflags, - pflags, mntdata, optional, dev, relative, rootfs_path); + ret = mount_entry(mntent->mnt_fsname, + path, + mntent->mnt_type, + opts.mnt_flags, + opts.prop_flags, + opts.data, + optional, + dev, + relative, + rootfs_path); return ret; } From 0ef1dbb17bbf0ee69abda48673a65f0eccc8ecfa Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 26 Aug 2021 13:38:07 +0200 Subject: [PATCH 11/15] conf: remove unused variables Signed-off-by: Christian Brauner --- src/lxc/conf.c | 30 ------------------------------ src/lxc/conf.h | 6 ------ src/lxc/confile.c | 1 - 3 files changed, 37 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 12fc7fa26..8070a32b1 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -3390,8 +3390,6 @@ struct lxc_conf *lxc_conf_init(void) INIT_LIST_HEAD(&new->id_map); new->root_nsuid_map = NULL; new->root_nsgid_map = NULL; - lxc_list_init(&new->includes); - lxc_list_init(&new->aliens); lxc_list_init(&new->environment); INIT_LIST_HEAD(&new->limits); INIT_LIST_HEAD(&new->sysctls); @@ -4743,32 +4741,6 @@ int lxc_clear_hooks(struct lxc_conf *c, const char *key) return 0; } -static inline void lxc_clear_aliens(struct lxc_conf *conf) -{ - struct lxc_list *it, *next; - - lxc_list_for_each_safe (it, &conf->aliens, next) { - lxc_list_del(it); - free(it->elem); - free(it); - } - - lxc_list_init(&conf->aliens); -} - -void lxc_clear_includes(struct lxc_conf *conf) -{ - struct lxc_list *it, *next; - - lxc_list_for_each_safe(it, &conf->includes, next) { - lxc_list_del(it); - free(it->elem); - free(it); - } - - lxc_list_init(&conf->includes); -} - int lxc_clear_apparmor_raw(struct lxc_conf *c) { struct lxc_list *it, *next; @@ -4824,8 +4796,6 @@ void lxc_conf_free(struct lxc_conf *conf) lxc_clear_mount_entries(conf); lxc_clear_idmaps(conf); lxc_clear_groups(conf); - lxc_clear_includes(conf); - lxc_clear_aliens(conf); lxc_clear_environment(conf); lxc_clear_limits(conf, "lxc.prlimit"); lxc_clear_sysctls(conf, "lxc.sysctl"); diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 0843c99ad..1449774e4 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -436,11 +436,6 @@ struct lxc_conf { unsigned int monitor_unshare; unsigned int monitor_signal_pdeath; - /* list of included files */ - struct lxc_list includes; - /* config entries which are not "lxc.*" are aliens */ - struct lxc_list aliens; - /* list of environment variables we'll add to the container when * started */ struct lxc_list environment; @@ -540,7 +535,6 @@ __hidden extern int lxc_clear_environment(struct lxc_conf *c); __hidden extern int lxc_clear_limits(struct lxc_conf *c, const char *key); __hidden extern int lxc_delete_autodev(struct lxc_handler *handler); __hidden extern int lxc_clear_autodev_tmpfs_size(struct lxc_conf *c); -__hidden extern void lxc_clear_includes(struct lxc_conf *conf); __hidden extern int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const char *name, const char *lxcpath); __hidden extern int lxc_setup(struct lxc_handler *handler); diff --git a/src/lxc/confile.c b/src/lxc/confile.c index d0b891d2d..6c05838a2 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -5257,7 +5257,6 @@ static inline int clr_config_proc(const char *key, struct lxc_conf *c, static inline int clr_config_includefiles(const char *key, struct lxc_conf *c, void *data) { - lxc_clear_includes(c); return 0; } From c294a68d1364c874521404fdcf82c53a6ab9e8db Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 26 Aug 2021 14:11:48 +0200 Subject: [PATCH 12/15] conf: port environment to new list type Signed-off-by: Christian Brauner --- src/lxc/attach.c | 15 +++------------ src/lxc/conf.c | 32 +++++++++++++++++++++++++------- src/lxc/conf.h | 10 +++++++++- src/lxc/confile.c | 45 +++++++++++++++++++++++++-------------------- src/lxc/start.c | 32 +++++++++++--------------------- 5 files changed, 73 insertions(+), 61 deletions(-) diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 396001963..5668fd035 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -782,7 +782,6 @@ static int lxc_attach_set_environment(struct attach_context *ctx, char **extra_env, char **extra_keep) { int ret; - struct lxc_list *iterator; if (policy == LXC_ATTACH_CLEAR_ENV) { int path_kept = 0; @@ -863,17 +862,9 @@ static int lxc_attach_set_environment(struct attach_context *ctx, /* Set container environment variables.*/ if (ctx->container->lxc_conf) { - lxc_list_for_each(iterator, &ctx->container->lxc_conf->environment) { - char *env_tmp; - - env_tmp = strdup((char *)iterator->elem); - if (!env_tmp) - return -1; - - ret = putenv(env_tmp); - if (ret < 0) - return log_error_errno(-1, errno, "Failed to set environment variable: %s", (char *)iterator->elem); - } + ret = lxc_set_environment(ctx->container->lxc_conf); + if (ret < 0) + return -1; } /* Set extra environment variables. */ diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 8070a32b1..fa1777699 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -3390,7 +3390,7 @@ struct lxc_conf *lxc_conf_init(void) INIT_LIST_HEAD(&new->id_map); new->root_nsuid_map = NULL; new->root_nsgid_map = NULL; - lxc_list_init(&new->environment); + INIT_LIST_HEAD(&new->environment); INIT_LIST_HEAD(&new->limits); INIT_LIST_HEAD(&new->sysctls); INIT_LIST_HEAD(&new->procs); @@ -4677,15 +4677,16 @@ int lxc_clear_groups(struct lxc_conf *c) int lxc_clear_environment(struct lxc_conf *c) { - struct lxc_list *it, *next; + struct environment_entry *env, *nenv; - lxc_list_for_each_safe (it, &c->environment, next) { - lxc_list_del(it); - free(it->elem); - free(it); + list_for_each_entry_safe(env, nenv, &c->environment, head) { + list_del(&env->head); + free(env->key); + free(env->val); + free(env); } - lxc_list_init(&c->environment); + INIT_LIST_HEAD(&c->environment); return 0; } @@ -5726,3 +5727,20 @@ void sort_cgroup_settings(struct lxc_conf *conf) } } } + +int lxc_set_environment(const struct lxc_conf *conf) +{ + struct environment_entry *env; + + list_for_each_entry(env, &conf->environment, head) { + int ret; + + ret = setenv(env->key, env->val, 1); + if (ret < 0) + return syserror("Failed to set environment variable: %s=%s", + env->key, env->val); + TRACE("Set environment variable: %s=%s", env->key, env->val); + } + + return 0; +} diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 1449774e4..0ec423458 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -337,6 +337,12 @@ struct timens_offsets { int64_t ns_monotonic; }; +struct environment_entry { + char *key; + char *val; + struct list_head head; +}; + struct lxc_conf { /* Pointer to the name of the container. Do not free! */ const char *name; @@ -438,7 +444,7 @@ struct lxc_conf { /* list of environment variables we'll add to the container when * started */ - struct lxc_list environment; + struct list_head environment; /* text representation of the config file */ char *unexpanded_config; @@ -643,4 +649,6 @@ static inline int lxc_personality(personality_t persona) return personality(persona); } +__hidden extern int lxc_set_environment(const struct lxc_conf *conf); + #endif /* __LXC_CONF_H */ diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 6c05838a2..e9c241f56 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -1539,35 +1539,40 @@ static int set_config_group(const char *key, const char *value, static int set_config_environment(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { - __do_free struct lxc_list *list_item = NULL; + __do_free char *dup = NULL, *val = NULL; + __do_free struct environment_entry *new_env = NULL; + char *env_val; if (lxc_config_value_empty(value)) return lxc_clear_environment(lxc_conf); - list_item = lxc_list_new(); - if (!list_item) + new_env = zalloc(sizeof(struct environment_entry)); + if (!new_env) return ret_errno(ENOMEM); - if (!strchr(value, '=')) { - const char *env_val; - const char *env_key = value; - const char *env_var[3] = {0}; + dup = strdup(value); + if (!dup) + return ret_errno(ENOMEM); - env_val = getenv(env_key); - if (!env_val) - return ret_errno(ENOENT); - - env_var[0] = env_key; - env_var[1] = env_val; - list_item->elem = lxc_string_join("=", env_var, false); + env_val = strchr(dup, '='); + if (!env_val) { + env_val = getenv(dup); } else { - list_item->elem = strdup(value); + *env_val = '\0'; + env_val++; } + if (!env_val) + return ret_errno(ENOENT); - if (!list_item->elem) + val = strdup(env_val); + if (!val) return ret_errno(ENOMEM); - lxc_list_add_tail(&lxc_conf->environment, move_ptr(list_item)); + new_env->key = move_ptr(dup); + new_env->val = move_ptr(val); + + list_add_tail(&new_env->head, &lxc_conf->environment); + move_ptr(new_env); return 0; } @@ -4442,15 +4447,15 @@ static int get_config_environment(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { int len, fulllen = 0; - struct lxc_list *it; + struct environment_entry *env; if (!retv) inlen = 0; else memset(retv, 0, inlen); - lxc_list_for_each(it, &c->environment) { - strprint(retv, inlen, "%s\n", (char *)it->elem); + list_for_each_entry(env, &c->environment, head) { + strprint(retv, inlen, "%s=%s\n", env->key, env->val); } return fulllen; diff --git a/src/lxc/start.c b/src/lxc/start.c index 7041a913c..7f0903f1b 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1052,12 +1052,11 @@ static int do_start(void *data) { struct lxc_handler *handler = data; __lxc_unused __do_close int data_sock0 = handler->data_sock[0], - data_sock1 = handler->data_sock[1]; + data_sock1 = handler->data_sock[1]; __do_close int devnull_fd = -EBADF, status_fd = -EBADF; int ret; uid_t new_uid; gid_t new_gid; - struct lxc_list *iterator; uid_t nsuid = 0; gid_t nsgid = 0; @@ -1257,18 +1256,14 @@ static int do_start(void *data) } } - /* Add the requested environment variables to the current environment to - * allow them to be used by the various hooks, such as the start hook - * below. + /* + * Add the requested environment variables to the current environment + * to allow them to be used by the various hooks, such as the start + * hook below. */ - lxc_list_for_each(iterator, &handler->conf->environment) { - ret = putenv((char *)iterator->elem); - if (ret < 0) { - SYSERROR("Failed to set environment variable: %s", - (char *)iterator->elem); - goto out_warn_father; - } - } + ret = lxc_set_environment(handler->conf); + if (ret < 0) + goto out_warn_father; if (!lxc_sync_wait_parent(handler, START_SYNC_POST_CONFIGURE)) goto out_warn_father; @@ -1361,14 +1356,9 @@ static int do_start(void *data) if (ret < 0) SYSERROR("Failed to clear environment."); - lxc_list_for_each(iterator, &handler->conf->environment) { - ret = putenv((char *)iterator->elem); - if (ret < 0) { - SYSERROR("Failed to set environment variable: %s", - (char *)iterator->elem); - goto out_warn_father; - } - } + ret = lxc_set_environment(handler->conf); + if (ret < 0) + goto out_warn_father; ret = putenv("container=lxc"); if (ret < 0) { From 9ab399dfcfffdbaf3b5efa9358de1777f8b67f2d Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 26 Aug 2021 14:19:14 +0200 Subject: [PATCH 13/15] terminal: remove unused struct member Signed-off-by: Christian Brauner --- src/lxc/terminal.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lxc/terminal.h b/src/lxc/terminal.h index 816b73630..194f88711 100644 --- a/src/lxc/terminal.h +++ b/src/lxc/terminal.h @@ -30,7 +30,6 @@ struct lxc_terminal_info { }; struct lxc_terminal_state { - struct lxc_list node; int stdinfd; int stdoutfd; int ptxfd; From badf09ec16f498241ecb5c14ca318864cbdb27b2 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 26 Aug 2021 14:19:53 +0200 Subject: [PATCH 14/15] cgroup: remove unneeded forward declaration Signed-off-by: Christian Brauner --- src/lxc/cgroups/cgroup.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h index d057957b4..42285ff40 100644 --- a/src/lxc/cgroups/cgroup.h +++ b/src/lxc/cgroups/cgroup.h @@ -26,7 +26,6 @@ struct lxc_handler; struct lxc_conf; -struct lxc_list; typedef enum { CGROUP_LAYOUT_UNKNOWN = -1, From 20ab75789eb9bf779e496a3a971b635bad8637a2 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 26 Aug 2021 15:25:28 +0200 Subject: [PATCH 15/15] conf: simplify and port caps to new list type Signed-off-by: Christian Brauner --- src/lxc/conf.c | 158 +++++++++++++++++++--------------------------- src/lxc/conf.h | 23 ++++--- src/lxc/confile.c | 122 +++++++++++++++++++++-------------- 3 files changed, 155 insertions(+), 148 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index fa1777699..59cfbc940 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -828,17 +828,14 @@ static int lxc_mount_auto_mounts(struct lxc_handler *handler, int flags) * container can't remount it read-write. */ if ((cg_flags == LXC_AUTO_CGROUP_NOSPEC) || (cg_flags == LXC_AUTO_CGROUP_FULL_NOSPEC)) { - int has_sys_admin = 0; - - if (!lxc_list_empty(&conf->keepcaps)) - has_sys_admin = in_caplist(CAP_SYS_ADMIN, &conf->keepcaps); - else - has_sys_admin = !in_caplist(CAP_SYS_ADMIN, &conf->caps); - if (cg_flags == LXC_AUTO_CGROUP_NOSPEC) - cg_flags = has_sys_admin ? LXC_AUTO_CGROUP_RW : LXC_AUTO_CGROUP_MIXED; + cg_flags = has_cap(CAP_SYS_ADMIN, conf) + ? LXC_AUTO_CGROUP_RW + : LXC_AUTO_CGROUP_MIXED; else - cg_flags = has_sys_admin ? LXC_AUTO_CGROUP_FULL_RW : LXC_AUTO_CGROUP_FULL_MIXED; + cg_flags = has_cap(CAP_SYS_ADMIN, conf) + ? LXC_AUTO_CGROUP_FULL_RW + : LXC_AUTO_CGROUP_FULL_MIXED; } if (flags & LXC_AUTO_CGROUP_FORCE) @@ -3105,7 +3102,7 @@ out: return fret; } -static int parse_cap(const char *cap) +int parse_cap(const char *cap) { size_t i; int capid = -1; @@ -3142,86 +3139,70 @@ static int parse_cap(const char *cap) return capid; } -int in_caplist(int cap, struct lxc_list *caps) +bool has_cap(int cap, struct lxc_conf *conf) { - int capid; - struct lxc_list *iterator; + bool cap_in_list = false; + struct cap_entry *cap_entry; - lxc_list_for_each (iterator, caps) { - capid = parse_cap(iterator->elem); - if (capid == cap) - return 1; + list_for_each_entry(cap_entry, &conf->caps.list, head) { + if (cap_entry->cap != cap) + continue; + + cap_in_list = true; } - return 0; + /* The capability is kept. */ + if (conf->caps.keep) + return cap_in_list; + + /* The capability is not dropped. */ + return !cap_in_list; } -static int setup_caps(struct lxc_list *caps) +static int setup_caps(struct lxc_conf *conf) { - int capid; - char *drop_entry; - struct lxc_list *iterator; + struct cap_entry *cap; - lxc_list_for_each (iterator, caps) { + list_for_each_entry(cap, &conf->caps.list, head) { int ret; - drop_entry = iterator->elem; - - capid = parse_cap(drop_entry); - if (capid < 0) - return log_error(-1, "unknown capability %s", drop_entry); - - ret = prctl(PR_CAPBSET_DROP, prctl_arg(capid), prctl_arg(0), + ret = prctl(PR_CAPBSET_DROP, prctl_arg(cap->cap), prctl_arg(0), prctl_arg(0), prctl_arg(0)); if (ret < 0) - return log_error_errno(-1, errno, "Failed to remove %s capability", drop_entry); - DEBUG("Dropped %s (%d) capability", drop_entry, capid); + return log_error_errno(-1, errno, "Failed to remove %s capability", cap->cap_name); + + DEBUG("Dropped %s (%d) capability", cap->cap_name, cap->cap); } DEBUG("Capabilities have been setup"); return 0; } -static int dropcaps_except(struct lxc_list *caps) +static int dropcaps_except(struct lxc_conf *conf) { - __do_free int *caplist = NULL; - int i, capid, numcaps; - char *keep_entry; - struct lxc_list *iterator; + int numcaps; + struct cap_entry *cap; numcaps = lxc_caps_last_cap() + 1; if (numcaps <= 0 || numcaps > 200) - return -1; + return ret_errno(EINVAL); + TRACE("Found %d capabilities", numcaps); - /* caplist[i] is 1 if we keep capability i */ - caplist = must_realloc(NULL, numcaps * sizeof(int)); - memset(caplist, 0, numcaps * sizeof(int)); - - lxc_list_for_each (iterator, caps) { - keep_entry = iterator->elem; - - capid = parse_cap(keep_entry); - if (capid == -2) - continue; - - if (capid < 0) - return log_error(-1, "Unknown capability %s", keep_entry); - - DEBUG("Keep capability %s (%d)", keep_entry, capid); - caplist[capid] = 1; - } - - for (i = 0; i < numcaps; i++) { + list_for_each_entry(cap, &conf->caps.list, head) { int ret; - if (caplist[i]) + if (cap->cap >= numcaps) continue; - ret = prctl(PR_CAPBSET_DROP, prctl_arg(i), prctl_arg(0), + ret = prctl(PR_CAPBSET_DROP, prctl_arg(cap->cap), prctl_arg(0), prctl_arg(0), prctl_arg(0)); if (ret < 0) - return log_error_errno(-1, errno, "Failed to remove capability %d", i); + return log_error_errno(-1, errno, + "Failed to remove capability %s (%d)", + cap->cap_name, cap->cap); + + DEBUG("Keep capability %s (%d)", cap->cap_name, cap->cap); } DEBUG("Capabilities have been setup"); @@ -3385,8 +3366,7 @@ struct lxc_conf *lxc_conf_init(void) new->bpf_devices.list_type = LXC_BPF_DEVICE_CGROUP_ALLOWLIST; INIT_LIST_HEAD(&(new->bpf_devices).devices); lxc_list_init(&new->mount_list); - lxc_list_init(&new->caps); - lxc_list_init(&new->keepcaps); + INIT_LIST_HEAD(&new->caps.list); INIT_LIST_HEAD(&new->id_map); new->root_nsuid_map = NULL; new->root_nsgid_map = NULL; @@ -4275,6 +4255,20 @@ int lxc_sync_fds_child(struct lxc_handler *handler) return 0; } +static int setcup_capabilities(struct lxc_conf *conf) +{ + int ret; + + if (conf->caps.keep) + ret = dropcaps_except(conf); + else + ret = setup_caps(conf); + if (ret < 0) + return log_error(-1, "Failed to %s capabilities", conf->caps.keep ? "keep" : "drop"); + + return 0; +} + int lxc_setup(struct lxc_handler *handler) { int ret; @@ -4418,15 +4412,9 @@ int lxc_setup(struct lxc_handler *handler) if (ret < 0) return log_error(-1, "Failed to setup sysctl parameters"); - if (!lxc_list_empty(&lxc_conf->keepcaps)) { - if (!lxc_list_empty(&lxc_conf->caps)) - return log_error(-1, "Container requests lxc.cap.drop and lxc.cap.keep: either use lxc.cap.drop or lxc.cap.keep, not both"); - - if (dropcaps_except(&lxc_conf->keepcaps)) - return log_error(-1, "Failed to keep capabilities"); - } else if (setup_caps(&lxc_conf->caps)) { - return log_error(-1, "Failed to drop capabilities"); - } + ret = setcup_capabilities(lxc_conf); + if (ret < 0) + return log_error(-1, "Failed to setup capabilities"); put_lxc_rootfs(&handler->conf->rootfs, true); NOTICE("The container \"%s\" is set up", name); @@ -4463,15 +4451,16 @@ int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf, int lxc_clear_config_caps(struct lxc_conf *c) { - struct lxc_list *it, *next; + struct cap_entry *cap, *ncap; - lxc_list_for_each_safe (it, &c->caps, next) { - lxc_list_del(it); - free(it->elem); - free(it); + list_for_each_entry_safe(cap, ncap, &c->caps.list, head) { + list_del(&cap->head); + free(cap->cap_name); + free(cap); } - lxc_list_init(&c->caps); + c->caps.keep = false; + INIT_LIST_HEAD(&c->caps.list); return 0; } @@ -4500,20 +4489,6 @@ int lxc_clear_idmaps(struct lxc_conf *c) return lxc_free_idmap(&c->id_map); } -int lxc_clear_config_keepcaps(struct lxc_conf *c) -{ - struct lxc_list *it, *next; - - lxc_list_for_each_safe (it, &c->keepcaps, next) { - lxc_list_del(it); - free(it->elem); - free(it); - } - - lxc_list_init(&c->keepcaps); - return 0; -} - int lxc_clear_namespace(struct lxc_conf *c) { for (int i = 0; i < LXC_NS_MAX; i++) @@ -4789,7 +4764,6 @@ void lxc_conf_free(struct lxc_conf *conf) free(conf->lsm_se_keyring_context); lxc_seccomp_free(&conf->seccomp); lxc_clear_config_caps(conf); - lxc_clear_config_keepcaps(conf); lxc_clear_cgroups(conf, "lxc.cgroup", CGROUP_SUPER_MAGIC); lxc_clear_cgroups(conf, "lxc.cgroup2", CGROUP2_SUPER_MAGIC); lxc_clear_cgroups_devices(conf); diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 0ec423458..7cc41afd2 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -343,6 +343,17 @@ struct environment_entry { struct list_head head; }; +struct cap_entry { + char *cap_name; + int cap; + struct list_head head; +}; + +struct caps { + int keep; + struct list_head list; +}; + struct lxc_conf { /* Pointer to the name of the container. Do not free! */ const char *name; @@ -381,8 +392,7 @@ struct lxc_conf { struct lxc_list mount_list; }; - struct lxc_list caps; - struct lxc_list keepcaps; + struct caps caps; /* /dev/tty devices */ struct lxc_tty_info ttys; @@ -530,7 +540,6 @@ __hidden extern int lxc_map_ids(struct list_head *idmap, pid_t pid); __hidden extern int lxc_create_tty(const char *name, struct lxc_conf *conf); __hidden extern void lxc_delete_tty(struct lxc_tty_info *ttys); __hidden extern int lxc_clear_config_caps(struct lxc_conf *c); -__hidden extern int lxc_clear_config_keepcaps(struct lxc_conf *c); __hidden extern int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version); __hidden extern int lxc_clear_mount_entries(struct lxc_conf *c); __hidden extern int lxc_clear_automounts(struct lxc_conf *c); @@ -563,17 +572,14 @@ __hidden extern void sort_cgroup_settings(struct lxc_conf *conf); __hidden extern int run_script(const char *name, const char *section, const char *script, ...); __hidden extern int run_script_argv(const char *name, unsigned int hook_version, const char *section, const char *script, const char *hookname, char **argsin); -__hidden extern int in_caplist(int cap, struct lxc_list *caps); +__hidden extern bool has_cap(int cap, struct lxc_conf *conf); static inline bool lxc_wants_cap(int cap, struct lxc_conf *conf) { if (lxc_caps_last_cap() < cap) return false; - if (!lxc_list_empty(&conf->keepcaps)) - return in_caplist(cap, &conf->keepcaps); - - return !in_caplist(cap, &conf->caps); + return has_cap(cap, conf); } __hidden extern int setup_sysctl_parameters(struct lxc_conf *conf); @@ -650,5 +656,6 @@ static inline int lxc_personality(personality_t persona) } __hidden extern int lxc_set_environment(const struct lxc_conf *conf); +__hidden extern int parse_cap(const char *cap); #endif /* __LXC_CONF_H */ diff --git a/src/lxc/confile.c b/src/lxc/confile.c index e9c241f56..e46e021e0 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -2400,70 +2400,96 @@ int add_elem_to_mount_list(const char *value, struct lxc_conf *lxc_conf) { return set_config_mount(NULL, value, lxc_conf, NULL); } +static int add_cap_entry(struct lxc_conf *conf, char *caps, bool keep) +{ + char *token; + + /* + * In case several capability keep is specified in a single line split + * these caps in a single element for the list. + */ + lxc_iterate_parts(token, caps, " \t") { + __do_free struct cap_entry *new_cap = NULL; + int cap; + + if (strequal(token, "none")) { + if (!keep) + return syserror_set(-EINVAL, "The \"none\" keyword is only valid when keeping caps"); + + lxc_clear_config_caps(conf); + continue; + } + + cap = parse_cap(token); + if (cap < 0) { + if (cap != -2) + return syserror_set(-EINVAL, "Invalid capability specified"); + + INFO("Ignoring unknown capability \"%s\"", token); + continue; + } + + new_cap = zalloc(sizeof(struct cap_entry)); + if (!new_cap) + return ret_errno(ENOMEM); + + new_cap->cap_name = strdup(token); + if (!new_cap->cap_name) + return ret_errno(ENOMEM); + new_cap->cap = cap; + + list_add_tail(&new_cap->head, &conf->caps.list); + move_ptr(new_cap); + } + + return 0; +} + static int set_config_cap_keep(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { - __do_free char *keepcaps = NULL; - __do_free struct lxc_list *keeplist = NULL; - char *token; + __do_free char *caps = NULL; + int ret; if (lxc_config_value_empty(value)) - return lxc_clear_config_keepcaps(lxc_conf); + return lxc_clear_config_caps(lxc_conf); - keepcaps = strdup(value); - if (!keepcaps) + caps = strdup(value); + if (!caps) return ret_errno(ENOMEM); - /* In case several capability keep is specified in a single line - * split these caps in a single element for the list. - */ - lxc_iterate_parts(token, keepcaps, " \t") { - if (strequal(token, "none")) - lxc_clear_config_keepcaps(lxc_conf); + if (!lxc_conf->caps.keep && !list_empty(&lxc_conf->caps.list)) + return syserror_set(-EINVAL, "Keeping and dropping capabilities are mutually exclusive"); - keeplist = lxc_list_new(); - if (!keeplist) - return ret_errno(ENOMEM); - - keeplist->elem = strdup(token); - if (!keeplist->elem) - return ret_errno(ENOMEM); - - lxc_list_add_tail(&lxc_conf->keepcaps, move_ptr(keeplist)); - } + ret = add_cap_entry(lxc_conf, caps, true); + if (ret < 0) + return ret; + lxc_conf->caps.keep = true; return 0; } static int set_config_cap_drop(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { - __do_free char *dropcaps = NULL; - __do_free struct lxc_list *droplist = NULL; - char *token; + __do_free char *caps = NULL; + int ret; if (lxc_config_value_empty(value)) return lxc_clear_config_caps(lxc_conf); - dropcaps = strdup(value); - if (!dropcaps) + if (lxc_conf->caps.keep) + return syserror_set(-EINVAL, "Keeping and dropping capabilities are mutually exclusive"); + + caps = strdup(value); + if (!caps) return ret_errno(ENOMEM); - /* In case several capability drop is specified in a single line - * split these caps in a single element for the list. - */ - lxc_iterate_parts(token, dropcaps, " \t") { - droplist = lxc_list_new(); - if (!droplist) - return ret_errno(ENOMEM); - - droplist->elem = strdup(token); - if (!droplist->elem) - return ret_errno(ENOMEM); - - lxc_list_add_tail(&lxc_conf->caps, move_ptr(droplist)); - } + ret = add_cap_entry(lxc_conf, caps, false); + if (ret < 0) + return ret; + lxc_conf->caps.keep = false; return 0; } @@ -4255,15 +4281,15 @@ static int get_config_cap_drop(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { int len, fulllen = 0; - struct lxc_list *it; + struct cap_entry *cap; if (!retv) inlen = 0; else memset(retv, 0, inlen); - lxc_list_for_each(it, &c->caps) { - strprint(retv, inlen, "%s\n", (char *)it->elem); + list_for_each_entry(cap, &c->caps.list, head) { + strprint(retv, inlen, "%s\n", cap->cap_name); } return fulllen; @@ -4273,15 +4299,15 @@ static int get_config_cap_keep(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { int len, fulllen = 0; - struct lxc_list *it; + struct cap_entry *cap; if (!retv) inlen = 0; else memset(retv, 0, inlen); - lxc_list_for_each(it, &c->keepcaps) { - strprint(retv, inlen, "%s\n", (char *)it->elem); + list_for_each_entry(cap, &c->caps.list, head) { + strprint(retv, inlen, "%s\n", cap->cap_name); } return fulllen; @@ -5024,7 +5050,7 @@ static inline int clr_config_cap_drop(const char *key, struct lxc_conf *c, static inline int clr_config_cap_keep(const char *key, struct lxc_conf *c, void *data) { - return lxc_clear_config_keepcaps(c); + return lxc_clear_config_caps(c); } static inline int clr_config_console_path(const char *key, struct lxc_conf *c,