conf: record cgroup2 devices in parsed format

parent 6b500cc4
......@@ -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,
......
......@@ -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);
......
......@@ -2684,6 +2684,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);
......@@ -3823,6 +3824,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;
......@@ -4045,6 +4057,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);
......
......@@ -223,6 +223,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;
......@@ -235,6 +243,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 {
......
......@@ -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);
......
......@@ -65,4 +65,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 */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment