]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
conf: record cgroup2 devices in parsed format
authorChristian Brauner <christian.brauner@ubuntu.com>
Sat, 30 Nov 2019 15:05:44 +0000 (16:05 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Sun, 1 Dec 2019 10:56:43 +0000 (11:56 +0100)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/cgroups/cgfsng.c
src/lxc/cgroups/cgroup2_devices.c
src/lxc/conf.c
src/lxc/conf.h
src/lxc/log.h
src/lxc/memory_utils.h

index e2332abd105eacc2ac6339c4fa29fe1d27d68614..4b4a6a92a12d9176b5f74368ab3c8e3adfc66a2a 100644 (file)
@@ -2481,21 +2481,60 @@ out:
        return ret;
 }
 
+static int bpf_list_add_device(struct lxc_conf *conf, struct device_item *device)
+{
+       __do_free struct lxc_list *list_elem = NULL;
+       __do_free struct device_item *new_device = NULL;
+       struct lxc_list *it;
+
+       lxc_list_for_each(it, &conf->devices) {
+               struct device_item *cur = it->elem;
+
+               if (cur->type != device->type)
+                       continue;
+               if (cur->major != device->major)
+                       continue;
+               if (cur->minor != device->minor)
+                       continue;
+               if (strcmp(cur->access, device->access))
+                       continue;
+
+               /*
+                * The rule is switched from allow to deny or vica versa so
+                * don't bother allocating just flip the existing one.
+                */
+               if (cur->allow != device->allow) {
+                       cur->allow = device->allow;
+                       return log_trace(0, "Reusing existing rule of bpf device program: type %c, major %d, minor %d, access %s, allow %d",
+                                        cur->type, cur->major, cur->minor,
+                                        cur->access, cur->allow);
+               }
+       }
+
+       list_elem = malloc(sizeof(*list_elem));
+       if (!list_elem)
+               return error_log_errno(ENOMEM, "Failed to allocate new device list");
+
+       new_device = memdup(device, sizeof(struct device_item));
+       if (!new_device)
+               return error_log_errno(ENOMEM, "Failed to allocate new device item");
+
+       lxc_list_add_elem(list_elem, move_ptr(new_device));
+       lxc_list_add_tail(&conf->devices, move_ptr(list_elem));
+
+       return 0;
+}
+
 /*
  * Some of the parsing logic comes from the original cgroup device v1
  * implementation in the kernel.
  */
-static int bpf_device_cgroup_prepare(struct cgroup_ops *ops, const char *key,
+static int bpf_device_cgroup_prepare(struct cgroup_ops *ops,
+                                    struct lxc_conf *conf, const char *key,
                                     const char *val)
 {
 #ifdef HAVE_STRUCT_BPF_CGROUP_DEV_CTX
-       struct device_item {
-               char type;
-               int major;
-               int minor;
-               char access[100];
-               int allow;
-       } device_item = {0};
+       struct device_item device_item = {0};
        int count, ret;
        char temp[50];
        struct bpf_program *device;
@@ -2614,6 +2653,11 @@ static int bpf_device_cgroup_prepare(struct cgroup_ops *ops, const char *key,
                      device_item.type, device_item.major, device_item.minor,
                      device_item.access, device_item.allow);
        }
+
+       ret = bpf_list_add_device(conf, &device_item);
+       if (ret)
+               return -1;
+
 #endif
        return 0;
 }
@@ -2637,7 +2681,7 @@ static bool __cg_unified_setup_limits(struct cgroup_ops *ops,
                struct lxc_cgroup *cg = iterator->elem;
 
                if (strncmp("devices", cg->subsystem, 7) == 0) {
-                       ret = bpf_device_cgroup_prepare(ops, cg->subsystem,
+                       ret = bpf_device_cgroup_prepare(ops, conf, cg->subsystem,
                                                        cg->value);
                } else {
                        fullpath = must_make_path(h->container_full_path,
index d44ab328249bee22a7e75ef01013e0d18a4b9ab9..762fd14f6d4f3c69b736fde9c2d0b3e4cfc2d8e0 100644 (file)
@@ -7,7 +7,6 @@
 #endif
 #include <errno.h>
 #include <fcntl.h>
-#include <linux/filter.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -24,6 +23,7 @@
 
 #ifdef HAVE_STRUCT_BPF_CGROUP_DEV_CTX
 #include <linux/bpf.h>
+#include <linux/filter.h>
 
 lxc_log_define(cgroup2_devices, cgroup);
 
index c03b663835f0a3154ba4f2bdb93a5cfbddb549dd..1cb074b513f898ed01e71a82073ea75ad9361804 100644 (file)
@@ -2736,6 +2736,7 @@ struct lxc_conf *lxc_conf_init(void)
        new->logfd = -1;
        lxc_list_init(&new->cgroup);
        lxc_list_init(&new->cgroup2);
+       lxc_list_init(&new->devices);
        lxc_list_init(&new->network);
        lxc_list_init(&new->mount_list);
        lxc_list_init(&new->caps);
@@ -3883,6 +3884,17 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
        return 0;
 }
 
+static void lxc_clear_devices(struct lxc_conf *conf)
+{
+       struct lxc_list *list = &conf->devices;
+       struct lxc_list *it, *next;
+
+       lxc_list_for_each_safe(it, list, next) {
+               lxc_list_del(it);
+               free(it);
+       }
+}
+
 int lxc_clear_limits(struct lxc_conf *c, const char *key)
 {
        struct lxc_list *it, *next;
@@ -4119,6 +4131,7 @@ void lxc_conf_free(struct lxc_conf *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_devices(conf);
        lxc_clear_cgroup2_devices(conf);
        lxc_clear_hooks(conf, "lxc.hook");
        lxc_clear_mount_entries(conf);
index 741ac4f09617552181a818cc0ab60002d5ad5a63..44d7934fe4bf55980cfae9f2b788601856ff49e3 100644 (file)
@@ -230,6 +230,14 @@ struct lxc_state_client {
        lxc_state_t states[MAX_STATE];
 };
 
+struct device_item {
+       char type;
+       int major;
+       int minor;
+       char access[4];
+       int allow;
+};
+
 struct lxc_conf {
        /* Pointer to the name of the container. Do not free! */
        const char *name;
@@ -242,6 +250,8 @@ struct lxc_conf {
                struct lxc_list cgroup;
                struct lxc_list cgroup2;
                struct bpf_program *cgroup2_devices;
+               /* This should be reimplemented as a hashmap. */
+               struct lxc_list devices;
        };
 
        struct {
index 3c5be95c3797fdbd2bee7a885e1e6ef4341da0cb..8e459196436445fa6b9330f1ab7dbc604654c496 100644 (file)
@@ -512,6 +512,12 @@ ATTR_UNUSED static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo,        \
                -1;                              \
        })
 
+#define log_trace(__ret__, format, ...)              \
+       ({                                    \
+               TRACE(format, ##__VA_ARGS__); \
+               __ret__;                      \
+       })
+
 extern int lxc_log_fd;
 
 extern int lxc_log_syslog(int facility);
index b5220c18994f99f6719466f44945fa6980bc652b..660e147b7d6aabc3d976207801875e566f313e0d 100644 (file)
@@ -71,4 +71,12 @@ static inline void __auto_close__(int *fd)
 #define __do_fclose __attribute__((__cleanup__(__auto_fclose__)))
 #define __do_closedir __attribute__((__cleanup__(__auto_closedir__)))
 
+static inline void *memdup(const void *data, size_t len)
+{
+       void *copy = NULL;
+
+       copy = len ? malloc(len) : NULL;
+       return copy ? memcpy(copy, data, len) : NULL;
+}
+
 #endif /* __LXC_MEMORY_UTILS_H */