]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
conf: simplify and port caps to new list type 3952/head
authorChristian Brauner <christian.brauner@ubuntu.com>
Thu, 26 Aug 2021 13:25:28 +0000 (15:25 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Thu, 26 Aug 2021 13:25:28 +0000 (15:25 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/conf.c
src/lxc/conf.h
src/lxc/confile.c

index fa1777699a646f55b43a1609ede74b39298af663..59cfbc94052e3da377b0550491078dc4579fc6e8 100644 (file)
@@ -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);
index 0ec423458382fa218fb42fb50e9776f63bab277e..7cc41afd26faa83236e7544e0a65b95b1dca5ab8 100644 (file)
@@ -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<idx> 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 */
index e9c241f566c552d746cadfdc8220aa10b946c5cc..e46e021e0a7e3abd79f20350e7f4c5ba9d9aeea3 100644 (file)
@@ -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,