diff --git a/meson.build b/meson.build index ce321723..b595cec8 100644 --- a/meson.build +++ b/meson.build @@ -202,8 +202,6 @@ liblxcfs_sources = files( 'src/cgroups/cgfsng.c', 'src/cgroups/cgroup.c', 'src/cgroups/cgroup.h', - 'src/cgroups/cgroup2_devices.c', - 'src/cgroups/cgroup2_devices.h', 'src/cgroups/cgroup_utils.c', 'src/cgroups/cgroup_utils.h', 'src/cgroup_fuse.c', diff --git a/src/cgroups/cgfsng.c b/src/cgroups/cgfsng.c index 72a4503c..2d583c67 100644 --- a/src/cgroups/cgfsng.c +++ b/src/cgroups/cgfsng.c @@ -34,7 +34,6 @@ #include "../memory_utils.h" #include "../utils.h" #include "cgroup.h" -#include "cgroup2_devices.h" #include "cgroup_utils.h" /* Given a pointer to a null-terminated array of pointers, realloc to add one @@ -963,9 +962,6 @@ static int cg_unified_init(struct cgroup_ops *ops) new = add_hierarchy(&ops->hierarchies, delegatable, mountpoint, base_cgroup, CGROUP2_SUPER_MAGIC); - if (bpf_devices_cgroup_supported()) - new->bpf_device_controller = 1; - ops->cgroup_layout = CGROUP_LAYOUT_UNIFIED; ops->unified = new; diff --git a/src/cgroups/cgroup.c b/src/cgroups/cgroup.c index 5bf7f62d..490e0bfa 100644 --- a/src/cgroups/cgroup.c +++ b/src/cgroups/cgroup.c @@ -26,7 +26,6 @@ #include "../memory_utils.h" #include "cgroup.h" #include "cgroup_utils.h" -#include "cgroup2_devices.h" extern struct cgroup_ops *cgfsng_ops_init(void); diff --git a/src/cgroups/cgroup2_devices.c b/src/cgroups/cgroup2_devices.c deleted file mode 100644 index e2eab796..00000000 --- a/src/cgroups/cgroup2_devices.c +++ /dev/null @@ -1,456 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ - -/* Parts of this taken from systemd's implementation. */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../macro.h" -#include "../memory_utils.h" -#include "cgroup2_devices.h" - -#ifdef HAVE_STRUCT_BPF_CGROUP_DEV_CTX -#include -#include - -static int bpf_program_add_instructions(struct bpf_program *prog, - const struct bpf_insn *instructions, - size_t count) -{ - - struct bpf_insn *new_insn; - - if (prog->kernel_fd >= 0) - return log_error_errno(-1, EBUSY, "Refusing to update bpf cgroup program that's already loaded"); - - new_insn = realloc(prog->instructions, sizeof(struct bpf_insn) * (count + prog->n_instructions)); - if (!new_insn) - return log_error_errno(-1, ENOMEM, "Failed to reallocate bpf cgroup program"); - - prog->instructions = new_insn; - memcpy(prog->instructions + prog->n_instructions, instructions, - sizeof(struct bpf_insn) * count); - prog->n_instructions += count; - - return 0; -} - -void bpf_program_free(struct bpf_program *prog) -{ - if (!prog) - return; - - (void)bpf_program_cgroup_detach(prog); - - if (prog->kernel_fd >= 0) - close(prog->kernel_fd); - free(prog->instructions); - free(prog->attached_path); - free(prog); -} - -/* Memory load, dst_reg = *(uint *) (src_reg + off16) */ -#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \ - ((struct bpf_insn){.code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = OFF, \ - .imm = 0}) - -/* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */ -#define BPF_ALU32_IMM(OP, DST, IMM) \ - ((struct bpf_insn){.code = BPF_ALU | BPF_OP(OP) | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM}) - -/* Short form of mov, dst_reg = src_reg */ -#define BPF_MOV64_IMM(DST, IMM) \ - ((struct bpf_insn){.code = BPF_ALU64 | BPF_MOV | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM}) - -#define BPF_MOV32_REG(DST, SRC) \ - ((struct bpf_insn){.code = BPF_ALU | BPF_MOV | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0}) - -/* Conditional jumps against registers, if (dst_reg 'op' src_reg) goto pc + off16 */ -#define BPF_JMP_REG(OP, DST, SRC, OFF) \ - ((struct bpf_insn){.code = BPF_JMP | BPF_OP(OP) | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = OFF, \ - .imm = 0}) - -/* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */ -#define BPF_JMP_IMM(OP, DST, IMM, OFF) \ - ((struct bpf_insn){.code = BPF_JMP | BPF_OP(OP) | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = OFF, \ - .imm = IMM}) - -/* Program exit */ -#define BPF_EXIT_INSN() \ - ((struct bpf_insn){.code = BPF_JMP | BPF_EXIT, \ - .dst_reg = 0, \ - .src_reg = 0, \ - .off = 0, \ - .imm = 0}) - -static int bpf_access_mask(const char *acc) -{ - int mask = 0; - - if (!acc) - return mask; - - for (; *acc; acc++) - switch (*acc) { - case 'r': - mask |= BPF_DEVCG_ACC_READ; - break; - case 'w': - mask |= BPF_DEVCG_ACC_WRITE; - break; - case 'm': - mask |= BPF_DEVCG_ACC_MKNOD; - break; - default: - return -EINVAL; - } - - return mask; -} - -static int bpf_device_type(char type) -{ - switch (type) { - case 'a': - return 0; - case 'b': - return BPF_DEVCG_DEV_BLOCK; - case 'c': - return BPF_DEVCG_DEV_CHAR; - } - - return -1; -} - -static inline bool bpf_device_all_access(int access_mask) -{ - return (access_mask == (BPF_DEVCG_ACC_READ | BPF_DEVCG_ACC_WRITE | - BPF_DEVCG_ACC_MKNOD)); -} - -struct bpf_program *bpf_program_new(uint32_t prog_type) -{ - __do_free struct bpf_program *prog = NULL; - - prog = calloc(1, sizeof(struct bpf_program)); - if (!prog) - return NULL; - - prog->prog_type = prog_type; - prog->kernel_fd = -EBADF; - /* - * By default a allowlist is used unless the user tells us otherwise. - */ - prog->device_list_type = LXC_BPF_DEVICE_CGROUP_ALLOWLIST; - - return move_ptr(prog); -} - -int bpf_program_init(struct bpf_program *prog) -{ - if (!prog) - return ret_set_errno(-1, EINVAL); - - const struct bpf_insn pre_insn[] = { - /* load device type to r2 */ - BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct bpf_cgroup_dev_ctx, access_type)), - BPF_ALU32_IMM(BPF_AND, BPF_REG_2, 0xFFFF), - - /* load access type to r3 */ - BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct bpf_cgroup_dev_ctx, access_type)), - BPF_ALU32_IMM(BPF_RSH, BPF_REG_3, 16), - - /* load major number to r4 */ - BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, offsetof(struct bpf_cgroup_dev_ctx, major)), - - /* load minor number to r5 */ - BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1, offsetof(struct bpf_cgroup_dev_ctx, minor)), - }; - - return bpf_program_add_instructions(prog, pre_insn, ARRAY_SIZE(pre_insn)); -} - -int bpf_program_append_device(struct bpf_program *prog, struct device_item *device) -{ - int ret; - int jump_nr = 1; - struct bpf_insn bpf_access_decision[] = { - BPF_MOV64_IMM(BPF_REG_0, device->allow), - BPF_EXIT_INSN(), - }; - int access_mask; - int device_type; - - if (!prog || !device) - return ret_set_errno(-1, EINVAL); - - /* This is a global rule so no need to append anything. */ - if (device->global_rule > LXC_BPF_DEVICE_CGROUP_LOCAL_RULE) { - prog->device_list_type = device->global_rule; - return 0; - } - - device_type = bpf_device_type(device->type); - if (device_type < 0) - return log_error_errno(-1, EINVAL, "Invalid bpf cgroup device type %c", device->type); - - if (device_type > 0) - jump_nr++; - - access_mask = bpf_access_mask(device->access); - if (!bpf_device_all_access(access_mask)) - jump_nr += 3; - - if (device->major != -1) - jump_nr++; - - if (device->minor != -1) - jump_nr++; - - if (device_type > 0) { - struct bpf_insn ins[] = { - BPF_JMP_IMM(BPF_JNE, BPF_REG_2, device_type, jump_nr--), - }; - - ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins)); - if (ret) - return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program"); - } - - if (!bpf_device_all_access(access_mask)) { - struct bpf_insn ins[] = { - BPF_MOV32_REG(BPF_REG_1, BPF_REG_3), - BPF_ALU32_IMM(BPF_AND, BPF_REG_1, access_mask), - BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, jump_nr), - }; - - jump_nr -= 3; - ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins)); - if (ret) - return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program"); - } - - if (device->major >= 0) { - struct bpf_insn ins[] = { - BPF_JMP_IMM(BPF_JNE, BPF_REG_4, device->major, jump_nr--), - }; - - ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins)); - if (ret) - return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program"); - } - - if (device->minor >= 0) { - struct bpf_insn ins[] = { - BPF_JMP_IMM(BPF_JNE, BPF_REG_5, device->minor, jump_nr--), - }; - - ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins)); - if (ret) - return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program"); - } - - ret = bpf_program_add_instructions(prog, bpf_access_decision, - ARRAY_SIZE(bpf_access_decision)); - if (ret) - return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program"); - - return 0; -} - -int bpf_program_finalize(struct bpf_program *prog) -{ - struct bpf_insn ins[] = { - BPF_MOV64_IMM(BPF_REG_0, prog->device_list_type), - BPF_EXIT_INSN(), - }; - - if (!prog) - return ret_set_errno(-1, EINVAL); - - TRACE("Implementing %s bpf device cgroup program", - prog->device_list_type == LXC_BPF_DEVICE_CGROUP_DENYLIST - ? "denylist" - : "allowlist"); - return bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins)); -} - -static int bpf_program_load_kernel(struct bpf_program *prog, char *log_buf, - size_t log_size) -{ - union bpf_attr attr; - - if (prog->kernel_fd >= 0) { - memset(log_buf, 0, log_size); - return 0; - } - - attr = (union bpf_attr){ - .prog_type = prog->prog_type, - .insns = PTR_TO_UINT64(prog->instructions), - .insn_cnt = prog->n_instructions, - .license = PTR_TO_UINT64("GPL"), - .log_buf = PTR_TO_UINT64(log_buf), - .log_level = !!log_buf, - .log_size = log_size, - }; - - prog->kernel_fd = bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); - if (prog->kernel_fd < 0) - return log_error_errno(-1, errno, "Failed to load bpf program"); - - return 0; -} - -int bpf_program_cgroup_attach(struct bpf_program *prog, int type, - const char *path, uint32_t flags) -{ - __do_free char *copy = NULL; - __do_close int fd = -EBADF; - union bpf_attr attr; - int ret; - - if (!prog) - return ret_set_errno(-1, EINVAL); - - if (flags & ~(BPF_F_ALLOW_OVERRIDE, BPF_F_ALLOW_MULTI)) - return log_error_errno(-1, EINVAL, "Invalid flags for bpf program"); - - if (prog->attached_path) { - if (prog->attached_type != type) - return log_error_errno(-1, EBUSY, "Wrong type for bpf program"); - - if (prog->attached_flags != flags) - return log_error_errno(-1, EBUSY, "Wrong flags for bpf program"); - - if (flags != BPF_F_ALLOW_OVERRIDE) - return true; - } - - ret = bpf_program_load_kernel(prog, NULL, 0); - if (ret < 0) - return log_error_errno(-1, ret, "Failed to load bpf program"); - - copy = strdup(path); - if (!copy) - return log_error_errno(-1, ENOMEM, "Failed to duplicate cgroup path %s", path); - - fd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC); - if (fd < 0) - return log_error_errno(-1, errno, "Failed to open cgroup path %s", path); - - attr = (union bpf_attr){ - .attach_type = type, - .target_fd = fd, - .attach_bpf_fd = prog->kernel_fd, - .attach_flags = flags, - }; - - ret = bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)); - if (ret < 0) - return log_error_errno(-1, errno, "Failed to attach bpf program"); - - free_replace_move_ptr(prog->attached_path, copy); - prog->attached_type = type; - prog->attached_flags = flags; - - TRACE("Loaded and attached bpf program to cgroup %s", prog->attached_path); - return 0; -} - -int bpf_program_cgroup_detach(struct bpf_program *prog) -{ - int ret; - __do_close int fd = -EBADF; - - if (!prog) - return 0; - - if (!prog->attached_path) - return 0; - - fd = open(prog->attached_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC); - if (fd < 0) { - if (errno != ENOENT) - return log_error_errno(-1, errno, "Failed to open attach cgroup %s", - prog->attached_path); - } else { - union bpf_attr attr; - - attr = (union bpf_attr){ - .attach_type = prog->attached_type, - .target_fd = fd, - .attach_bpf_fd = prog->kernel_fd, - }; - - ret = bpf(BPF_PROG_DETACH, &attr, sizeof(attr)); - if (ret < 0) - return log_error_errno(-1, errno, "Failed to detach bpf program from cgroup %s", - prog->attached_path); - } - - free(prog->attached_path); - prog->attached_path = NULL; - - return 0; -} - -bool bpf_devices_cgroup_supported(void) -{ - const struct bpf_insn dummy[] = { - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }; - - __do_bpf_program_free struct bpf_program *prog = NULL; - int ret; - - if (geteuid() != 0) - return log_trace(false, - "The bpf device cgroup requires real root"); - - prog = bpf_program_new(BPF_PROG_TYPE_CGROUP_DEVICE); - if (prog < 0) - return log_trace(false, "Failed to allocate new bpf device cgroup program"); - - ret = bpf_program_add_instructions(prog, dummy, ARRAY_SIZE(dummy)); - if (ret < 0) - return log_trace(false, "Failed to add new instructions to bpf device cgroup program"); - - ret = bpf_program_load_kernel(prog, NULL, 0); - if (ret < 0) - return log_trace(false, "Failed to load new bpf device cgroup program"); - - return log_trace(true, "The bpf device cgroup is supported"); -} -#endif diff --git a/src/cgroups/cgroup2_devices.h b/src/cgroups/cgroup2_devices.h deleted file mode 100644 index 6de10216..00000000 --- a/src/cgroups/cgroup2_devices.h +++ /dev/null @@ -1,136 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ - -/* Parts of this taken from systemd's implementation. */ - -#ifndef __LXC_CGROUP2_DEVICES_H -#define __LXC_CGROUP2_DEVICES_H - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_STRUCT_BPF_CGROUP_DEV_CTX -#include -#include -#endif - -#include "../syscall_numbers.h" - -#if !HAVE_BPF - -union bpf_attr; - -enum { - LXC_BPF_DEVICE_CGROUP_LOCAL_RULE = -1, - LXC_BPF_DEVICE_CGROUP_ALLOWLIST = 0, - LXC_BPF_DEVICE_CGROUP_DENYLIST = 1, -}; - -static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) -{ - return (int)syscall(__NR_bpf, cmd, attr, size); -} - -#define bpf missing_bpf -#endif - -struct bpf_program { - int device_list_type; - int kernel_fd; - uint32_t prog_type; - - size_t n_instructions; -#ifdef HAVE_STRUCT_BPF_CGROUP_DEV_CTX - struct bpf_insn *instructions; -#endif /* HAVE_STRUCT_BPF_CGROUP_DEV_CTX */ - - char *attached_path; - int attached_type; - uint32_t attached_flags; -}; - -#ifdef HAVE_STRUCT_BPF_CGROUP_DEV_CTX -struct bpf_program *bpf_program_new(uint32_t prog_type); -int bpf_program_init(struct bpf_program *prog); -int bpf_program_append_device(struct bpf_program *prog, - struct device_item *device); -int bpf_program_finalize(struct bpf_program *prog); -int bpf_program_cgroup_attach(struct bpf_program *prog, int type, - const char *path, uint32_t flags); -int bpf_program_cgroup_detach(struct bpf_program *prog); -void bpf_program_free(struct bpf_program *prog); -bool bpf_devices_cgroup_supported(void); -static inline void __auto_bpf_program_free__(struct bpf_program **prog) -{ - if (*prog) { - bpf_program_free(*prog); - *prog = NULL; - } -} -#else /* HAVE_STRUCT_BPF_CGROUP_DEV_CTX */ -static inline struct bpf_program *bpf_program_new(uint32_t prog_type) -{ - errno = ENOSYS; - return NULL; -} - -static inline int bpf_program_init(struct bpf_program *prog) -{ - errno = ENOSYS; - return -1; -} - -static inline int bpf_program_append_device(struct bpf_program *prog, char type, - int major, int minor, - const char *access, int allow) -{ - errno = ENOSYS; - return -1; -} - -static inline int bpf_program_finalize(struct bpf_program *prog) -{ - errno = ENOSYS; - return -1; -} - -static inline int bpf_program_cgroup_attach(struct bpf_program *prog, int type, - const char *path, uint32_t flags) -{ - errno = ENOSYS; - return -1; -} - -static inline int bpf_program_cgroup_detach(struct bpf_program *prog) -{ - errno = ENOSYS; - return -1; -} - -static inline void bpf_program_free(struct bpf_program *prog) -{ -} - - -static inline bool bpf_devices_cgroup_supported(void) -{ - return false; -} - -static inline void __auto_bpf_program_free__(struct bpf_program **prog) -{ -} - -#endif /* HAVE_BPF */ - -define_cleanup_function(struct bpf_program *, bpf_program_free); - -#endif /* __LXC_CGROUP2_DEVICES_H */