Skip to content

Commit

Permalink
bpf-restrict-fs: preserve cgroup_hash map during PID1 reexecution
Browse files Browse the repository at this point in the history
When PID1 is reexecuted, "cgroup_hash" map was destroyed and the "restrict_fs"
eBPF program was restarted with a new and empty map, loosing all entries for
previously registered services with RestrictFileSystem= set:

   $ systemctl start test-restrict-fs.service

   $ bpftool map dump name cgroup_hash
   key: dd 0e 00 00 00 00 00 00  inner_map_id: 21
   Found 1 element

   $ systemctl daemon-reexec

   $ bpftool map dump name cgroup_hash
   Found 0 elements

This patch fixes this issue by preserving the eBPF map and by reusing it when
"restrict_fs" is being initialized again during PID reexec.
  • Loading branch information
fbuihuu committed May 6, 2024
1 parent 5a99749 commit f22e47c
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 37 deletions.
56 changes: 29 additions & 27 deletions src/core/bpf-restrict-fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ static bool bpf_can_link_lsm_program(struct bpf_program *prog) {
return sym_libbpf_get_error(link) == 0;
}

static int prepare_restrict_fs_bpf(struct restrict_fs_bpf **ret_obj) {
static int prepare_restrict_fs_bpf(struct restrict_fs_bpf **ret_obj, int map_fd) {
_cleanup_(restrict_fs_bpf_freep) struct restrict_fs_bpf *obj = NULL;
_cleanup_close_ int inner_map_fd = -EBADF;
int r;
Expand All @@ -65,22 +65,28 @@ static int prepare_restrict_fs_bpf(struct restrict_fs_bpf **ret_obj) {
if (!obj)
return log_error_errno(errno, "bpf-restrict-fs: Failed to open BPF object: %m");

/* TODO Maybe choose a number based on runtime information? */
r = sym_bpf_map__set_max_entries(obj->maps.cgroup_hash, CGROUP_HASH_SIZE_MAX);
assert(r <= 0);
if (r < 0)
return log_error_errno(r, "bpf-restrict-fs: Failed to resize BPF map '%s': %m",
sym_bpf_map__name(obj->maps.cgroup_hash));

/* Dummy map to satisfy the verifier */
inner_map_fd = compat_bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(uint32_t), sizeof(uint32_t), 128U, NULL);
if (inner_map_fd < 0)
return log_error_errno(errno, "bpf-restrict-fs: Failed to create BPF map: %m");

r = sym_bpf_map__set_inner_map_fd(obj->maps.cgroup_hash, inner_map_fd);
assert(r <= 0);
if (r < 0)
return log_error_errno(r, "bpf-restrict-fs: Failed to set inner map fd: %m");
if (map_fd > 0) {
r = sym_bpf_map__reuse_fd(obj->maps.cgroup_hash, map_fd);
if (r < 0)
return log_error_errno(r, "bpf-restrict-fs: Failed to reuse map fd: %m");
} else {
/* TODO Maybe choose a number based on runtime information? */
r = sym_bpf_map__set_max_entries(obj->maps.cgroup_hash, CGROUP_HASH_SIZE_MAX);
assert(r <= 0);
if (r < 0)
return log_error_errno(r, "bpf-restrict-fs: Failed to resize BPF map '%s': %m",
sym_bpf_map__name(obj->maps.cgroup_hash));

/* Dummy map to satisfy the verifier */
inner_map_fd = compat_bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(uint32_t), sizeof(uint32_t), 128U, NULL);
if (inner_map_fd < 0)
return log_error_errno(errno, "bpf-restrict-fs: Failed to create BPF map: %m");

r = sym_bpf_map__set_inner_map_fd(obj->maps.cgroup_hash, inner_map_fd);
assert(r <= 0);
if (r < 0)
return log_error_errno(r, "bpf-restrict-fs: Failed to set inner map fd: %m");
}

r = restrict_fs_bpf__load(obj);
assert(r <= 0);
Expand Down Expand Up @@ -115,7 +121,7 @@ bool bpf_restrict_fs_supported(bool initialize) {
return (supported = false);
}

r = prepare_restrict_fs_bpf(&obj);
r = prepare_restrict_fs_bpf(&obj, /* map_fd= */ -EBADF);
if (r < 0)
return (supported = false);

Expand All @@ -134,7 +140,7 @@ int bpf_restrict_fs_setup(Manager *m) {

assert(m);

r = prepare_restrict_fs_bpf(&obj);
r = prepare_restrict_fs_bpf(&obj, m->pin_restrict_fs_map_fd);
if (r < 0)
return r;

Expand Down Expand Up @@ -237,14 +243,10 @@ int bpf_restrict_fs_cleanup(Unit *u) {
return 0;
}

int bpf_restrict_fs_map_fd(Unit *unit) {
assert(unit);
assert(unit->manager);

if (!unit->manager->restrict_fs)
return -ENOMEDIUM;
int bpf_restrict_fs_map_fd(struct restrict_fs_bpf *prog) {
assert(prog);

return sym_bpf_map__fd(unit->manager->restrict_fs->maps.cgroup_hash);
return sym_bpf_map__fd(prog->maps.cgroup_hash);
}

void bpf_restrict_fs_destroy(struct restrict_fs_bpf *prog) {
Expand All @@ -267,7 +269,7 @@ int bpf_restrict_fs_cleanup(Unit *u) {
return 0;
}

int bpf_restrict_fs_map_fd(Unit *unit) {
int bpf_restrict_fs_map_fd(struct restrict_fs_bpf *prog) {
return -ENOMEDIUM;
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/bpf-restrict-fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ bool bpf_restrict_fs_supported(bool initialize);
int bpf_restrict_fs_setup(Manager *m);
int bpf_restrict_fs_update(const Set *filesystems, uint64_t cgroup_id, int outer_map_fd, bool allow_list);
int bpf_restrict_fs_cleanup(Unit *u);
int bpf_restrict_fs_map_fd(Unit *u);
int bpf_restrict_fs_map_fd(struct restrict_fs_bpf *prog);
void bpf_restrict_fs_destroy(struct restrict_fs_bpf *prog);
int bpf_restrict_fs_parse_filesystem(const char *name, Set **filesystems, FilesystemParseFlags flags, const char *unit, const char *filename, unsigned line);
20 changes: 20 additions & 0 deletions src/core/manager-serialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,19 @@ int manager_serialize(
if (!switching_root)
(void) serialize_strv(f, "env", m->client_environment);

if (m->restrict_fs) {
int fd;

fd = bpf_restrict_fs_map_fd(m->restrict_fs);
if (fd < 0)
return fd;

r = serialize_fd(f, fds, "pin-restrict-fs-map-fd", fd);
if (r < 0)
return r;
}


if (m->notify_fd >= 0) {
r = serialize_fd(f, fds, "notify-fd", m->notify_fd);
if (r < 0)
Expand Down Expand Up @@ -450,6 +463,13 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
if (r < 0)
log_notice_errno(r, "Failed to parse environment entry: \"%s\", ignoring: %m", val);

} else if ((val = startswith(l, "pin-restrict-fs-map-fd="))) {
int fd;

fd = deserialize_fd(fds, val);
if (fd >= 0)
m->pin_restrict_fs_map_fd = fd;

} else if ((val = startswith(l, "notify-fd="))) {
int fd;

Expand Down
33 changes: 25 additions & 8 deletions src/core/manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,7 @@ int manager_new(RuntimeScope runtime_scope, ManagerTestRunFlags test_run_flags,
.private_listen_fd = -EBADF,
.dev_autofs_fd = -EBADF,
.cgroup_inotify_fd = -EBADF,
.pin_restrict_fs_map_fd = -EBADF,
.pin_cgroupfs_fd = -EBADF,
.ask_password_inotify_fd = -EBADF,
.idle_pipe = { -EBADF, -EBADF, -EBADF, -EBADF},
Expand Down Expand Up @@ -1019,14 +1020,6 @@ int manager_new(RuntimeScope runtime_scope, ManagerTestRunFlags test_run_flags,
r = manager_setup_memory_pressure_event_source(m);
if (r < 0)
return r;

#if HAVE_LIBBPF
if (MANAGER_IS_SYSTEM(m) && bpf_restrict_fs_supported(/* initialize = */ true)) {
r = bpf_restrict_fs_setup(m);
if (r < 0)
log_warning_errno(r, "Failed to setup LSM BPF, ignoring: %m");
}
#endif
}

if (test_run_flags == 0) {
Expand Down Expand Up @@ -1915,6 +1908,26 @@ static void manager_setup_bus(Manager *m) {
}
}


static int manager_setup_restrict_fs(Manager *m) {
int r = 0;

assert(m);

#if HAVE_LIBBPF
if (!MANAGER_IS_SYSTEM(m))
return 0;

if (!bpf_restrict_fs_supported(/* initialize = */ true))
return 0;

r = bpf_restrict_fs_setup(m);
if (r < 0)
log_warning_errno(r, "Failed to setup LSM BPF, ignoring: %m");
#endif
return r;
}

static void manager_preset_all(Manager *m) {
int r;

Expand Down Expand Up @@ -2066,6 +2079,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *roo
/* This shouldn't fail, except if things are really broken. */
return r;

r = manager_setup_restrict_fs(m);
if (r < 0)
return r;

/* Connect to the bus if we are good for it */
manager_setup_bus(m);

Expand Down
2 changes: 2 additions & 0 deletions src/core/manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ struct Manager {
* file system */
int pin_cgroupfs_fd;

int pin_restrict_fs_map_fd;

unsigned gc_marker;

/* The stat() data the last time we saw /etc/localtime */
Expand Down
2 changes: 1 addition & 1 deletion src/core/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -5371,7 +5371,7 @@ int unit_set_exec_params(Unit *u, ExecParameters *p) {
p->fallback_smack_process_label = u->manager->defaults.smack_process_label;

if (u->manager->restrict_fs && p->bpf_restrict_fs_map_fd < 0) {
int fd = bpf_restrict_fs_map_fd(u);
int fd = bpf_restrict_fs_map_fd(u->manager->restrict_fs);
if (fd < 0)
return fd;

Expand Down
2 changes: 2 additions & 0 deletions src/shared/bpf-dlopen.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ DLSYM_FUNCTION(bpf_link__open);
DLSYM_FUNCTION(bpf_link__pin);
DLSYM_FUNCTION(bpf_map__fd);
DLSYM_FUNCTION(bpf_map__name);
DLSYM_FUNCTION(bpf_map__reuse_fd);
DLSYM_FUNCTION(bpf_map__set_inner_map_fd);
DLSYM_FUNCTION(bpf_map__set_max_entries);
DLSYM_FUNCTION(bpf_map__set_pin_path);
Expand Down Expand Up @@ -134,6 +135,7 @@ int dlopen_bpf(void) {
DLSYM_ARG(bpf_link__pin),
DLSYM_ARG(bpf_map__fd),
DLSYM_ARG(bpf_map__name),
DLSYM_ARG(bpf_map__reuse_fd),
DLSYM_ARG(bpf_map__set_inner_map_fd),
DLSYM_ARG(bpf_map__set_max_entries),
DLSYM_ARG(bpf_map__set_pin_path),
Expand Down
1 change: 1 addition & 0 deletions src/shared/bpf-dlopen.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ DLSYM_PROTOTYPE(bpf_link__open);
DLSYM_PROTOTYPE(bpf_link__pin);
DLSYM_PROTOTYPE(bpf_map__fd);
DLSYM_PROTOTYPE(bpf_map__name);
DLSYM_PROTOTYPE(bpf_map__reuse_fd);
DLSYM_PROTOTYPE(bpf_map__set_inner_map_fd);
DLSYM_PROTOTYPE(bpf_map__set_max_entries);
DLSYM_PROTOTYPE(bpf_map__set_pin_path);
Expand Down

0 comments on commit f22e47c

Please sign in to comment.