From d9aeb6b23ecfd4013ff634ae0b116c3fe917951f Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 5 May 2020 19:04:21 +0200 Subject: [PATCH] ebpf: replace the existing program on update on a container update, make sure the existing eBPF program is completely replaced. Signed-off-by: Giuseppe Scrivano --- src/libcrun/cgroup.c | 45 ++++++++++++++++++++++++++++++++++++-------- src/libcrun/ebpf.c | 31 ++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/libcrun/cgroup.c b/src/libcrun/cgroup.c index d664b967f1..2e77660efd 100644 --- a/src/libcrun/cgroup.c +++ b/src/libcrun/cgroup.c @@ -1561,6 +1561,24 @@ libcrun_cgroup_killall (char *path, libcrun_error_t *err) return libcrun_cgroup_killall_signal (path, SIGKILL, err); } +static char * +get_bpf_pin_path (const char *path) +{ + char *pin_path = NULL; + int i; + + while (*path == '/') + path++; + + xasprintf (&pin_path, "/sys/fs/bpf/crun-%s", path); + + for (i = strlen ("/sys/fs/bpf/"); pin_path[i]; i++) + if (pin_path[i] == '/' || pin_path[i] == '.') + pin_path[i] = '-'; + + return pin_path; +} + int libcrun_cgroup_destroy (const char *id, char *path, int systemd_cgroup, libcrun_error_t *err) { @@ -1568,6 +1586,7 @@ libcrun_cgroup_destroy (const char *id, char *path, int systemd_cgroup, libcrun_ size_t i; int mode; const cgroups_subsystem_t *subsystems; + cleanup_free char *pin_path = NULL; (void) id; (void) systemd_cgroup; @@ -1618,6 +1637,9 @@ libcrun_cgroup_destroy (const char *id, char *path, int systemd_cgroup, libcrun_ } } + pin_path = get_bpf_pin_path (path); + unlink (pin_path); + return 0; } @@ -1966,10 +1988,11 @@ write_devices_resources_v1 (int dirfd, runtime_spec_schema_defs_linux_device_cgr } static int -write_devices_resources_v2_internal (int dirfd, runtime_spec_schema_defs_linux_device_cgroup **devs, size_t devs_len, libcrun_error_t *err) +write_devices_resources_v2_internal (const char *path, int dirfd, runtime_spec_schema_defs_linux_device_cgroup **devs, size_t devs_len, libcrun_error_t *err) { int i, ret; cleanup_free struct bpf_program *program = NULL; + cleanup_free char *pin_path = NULL; struct default_dev_s { char type; int major; @@ -2026,7 +2049,9 @@ write_devices_resources_v2_internal (int dirfd, runtime_spec_schema_defs_linux_d if (UNLIKELY (program == NULL)) return -1; - ret = libcrun_ebpf_load (program, dirfd, NULL, err); + pin_path = get_bpf_pin_path (path); + + ret = libcrun_ebpf_load (program, dirfd, pin_path, err); if (ret < 0) return ret; @@ -2034,13 +2059,13 @@ write_devices_resources_v2_internal (int dirfd, runtime_spec_schema_defs_linux_d } static int -write_devices_resources_v2 (int dirfd, runtime_spec_schema_defs_linux_device_cgroup **devs, size_t devs_len, libcrun_error_t *err) +write_devices_resources_v2 (const char *path, int dirfd, runtime_spec_schema_defs_linux_device_cgroup **devs, size_t devs_len, libcrun_error_t *err) { int ret; size_t i; bool can_skip = true; - ret = write_devices_resources_v2_internal (dirfd, devs, devs_len, err); + ret = write_devices_resources_v2_internal (path, dirfd, devs, devs_len, err); if (LIKELY (ret == 0)) return 0; @@ -2071,10 +2096,10 @@ write_devices_resources_v2 (int dirfd, runtime_spec_schema_defs_linux_device_cgr static int -write_devices_resources (int dirfd, bool cgroup2, runtime_spec_schema_defs_linux_device_cgroup **devs, size_t devs_len, libcrun_error_t *err) +write_devices_resources (const char *path, int dirfd, bool cgroup2, runtime_spec_schema_defs_linux_device_cgroup **devs, size_t devs_len, libcrun_error_t *err) { if (cgroup2) - return write_devices_resources_v2 (dirfd, devs, devs_len, err); + return write_devices_resources_v2 (path, dirfd, devs, devs_len, err); return write_devices_resources_v1 (dirfd, devs, devs_len, err); } @@ -2406,7 +2431,9 @@ update_cgroup_v1_resources (runtime_spec_schema_config_linux_resources *resource if (UNLIKELY (dirfd_devs < 0)) return crun_make_error (err, errno, "open %s", path_to_devs); - ret = write_devices_resources (dirfd_devs, false, + ret = write_devices_resources (path, + dirfd_devs, + false, resources->devices, resources->devices_len, err); @@ -2500,7 +2527,9 @@ update_cgroup_v2_resources (runtime_spec_schema_config_linux_resources *resource if (resources->devices_len) { - ret = write_devices_resources (cgroup_dirfd, true, + ret = write_devices_resources (path, + cgroup_dirfd, + true, resources->devices, resources->devices_len, err); diff --git a/src/libcrun/ebpf.c b/src/libcrun/ebpf.c index 8097746c59..8b325fdafa 100644 --- a/src/libcrun/ebpf.c +++ b/src/libcrun/ebpf.c @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef HAVE_EBPF # include @@ -299,7 +300,9 @@ libcrun_ebpf_load (struct bpf_program *program, int dirfd, const char *pin, libc #ifndef HAVE_EBPF return crun_make_error (err, 0, "eBPF not supported"); #else - int fd, ret; + cleanup_close int fd = -1; + cleanup_close int replacefd = -1; + int ret; union bpf_attr attr; struct rlimit limit; @@ -329,14 +332,36 @@ libcrun_ebpf_load (struct bpf_program *program, int dirfd, const char *pin, libc fd = bpf (BPF_PROG_LOAD, &attr, sizeof (attr)); if (fd < 0) - return crun_make_error (err, errno, "bpf create %s", log); + return crun_make_error (err, errno, "bpf create `%s`", log); + } + + if (pin) + { + union bpf_attr attr_open; + + memset (&attr_open, 0, sizeof (attr_open)); + attr_open.pathname = (uint64_t) pin; + + replacefd = bpf (BPF_OBJ_GET, &attr_open, sizeof (attr_open)); +#ifdef BPF_F_REPLACE + if (replacefd < 0 && errno != ENOENT) + return crun_make_error (err, errno, "open `%s`", pin); +#else + if (replacefd >= 0) + return crun_make_error (err, 0, "eBPF program already configured"); + #endif } memset (&attr, 0, sizeof (attr)); attr.attach_type = BPF_CGROUP_DEVICE; attr.target_fd = dirfd; attr.attach_bpf_fd = fd; +#ifdef BPF_F_REPLACE + attr.attach_flags = BPF_F_ALLOW_MULTI | ((replacefd >= 0) ? BPF_F_REPLACE : 0); + attr.replace_bpf_fd = replacefd; +#else attr.attach_flags = BPF_F_ALLOW_MULTI; +#endif ret = bpf (BPF_PROG_ATTACH, &attr, sizeof (attr)); if (ret < 0) @@ -345,6 +370,8 @@ libcrun_ebpf_load (struct bpf_program *program, int dirfd, const char *pin, libc /* Optionally pin the program to the specified path. */ if (pin) { + unlink (pin); + memset (&attr, 0, sizeof (attr)); attr.pathname = (uint64_t) pin; attr.bpf_fd = fd;