From: Christian Brauner Date: Thu, 26 Aug 2021 13:25:28 +0000 (+0200) Subject: conf: simplify and port caps to new list type X-Git-Tag: lxc-5.0.0~102^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=20ab75789eb9bf779e496a3a971b635bad8637a2;p=thirdparty%2Flxc.git conf: simplify and port caps to new list type Signed-off-by: Christian Brauner --- 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; - 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); + return ret_errno(EINVAL); - DEBUG("Keep capability %s (%d)", keep_entry, capid); - caplist[capid] = 1; - } + TRACE("Found %d capabilities", numcaps); - 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 set_config_cap_keep(const char *key, const char *value, - struct lxc_conf *lxc_conf, void *data) +static int add_cap_entry(struct lxc_conf *conf, char *caps, bool keep) { - __do_free char *keepcaps = NULL; - __do_free struct lxc_list *keeplist = NULL; char *token; - if (lxc_config_value_empty(value)) - return lxc_clear_config_keepcaps(lxc_conf); + /* + * 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; - keepcaps = strdup(value); - if (!keepcaps) - return ret_errno(ENOMEM); + if (strequal(token, "none")) { + if (!keep) + return syserror_set(-EINVAL, "The \"none\" keyword is only valid when keeping caps"); - /* 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); + 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; + } - keeplist = lxc_list_new(); - if (!keeplist) + new_cap = zalloc(sizeof(struct cap_entry)); + if (!new_cap) return ret_errno(ENOMEM); - keeplist->elem = strdup(token); - if (!keeplist->elem) + new_cap->cap_name = strdup(token); + if (!new_cap->cap_name) return ret_errno(ENOMEM); + new_cap->cap = cap; - lxc_list_add_tail(&lxc_conf->keepcaps, move_ptr(keeplist)); + list_add_tail(&new_cap->head, &conf->caps.list); + move_ptr(new_cap); } return 0; } -static int set_config_cap_drop(const char *key, const char *value, +static int set_config_cap_keep(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) + 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); + if (!lxc_conf->caps.keep && !list_empty(&lxc_conf->caps.list)) + return syserror_set(-EINVAL, "Keeping and dropping capabilities are mutually exclusive"); - droplist->elem = strdup(token); - if (!droplist->elem) - return ret_errno(ENOMEM); + ret = add_cap_entry(lxc_conf, caps, true); + if (ret < 0) + return ret; - lxc_list_add_tail(&lxc_conf->caps, move_ptr(droplist)); - } + 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 *caps = NULL; + int ret; + + if (lxc_config_value_empty(value)) + return lxc_clear_config_caps(lxc_conf); + 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); + + 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,