core: use LSM BPF functions to implement RestrictFileSystems=

It attaches the LSM BPF program when the system manager starts up.

It populates the hash of maps BPF map when services that have
RestrictFileSystems= set start.

It cleans up the hash of maps when the unit cgroup is pruned.

To pass the file descriptor of the BPF map we add it to the keep_fds
array.
This commit is contained in:
Iago Lopez Galeiras
2021-10-06 10:52:14 +02:00
parent 184b4f78cf
commit b1994387d3
7 changed files with 99 additions and 1 deletions
+60 -1
View File
@@ -41,6 +41,7 @@
#endif
#include "async.h"
#include "barrier.h"
#include "bpf-lsm.h"
#include "cap-list.h"
#include "capability-util.h"
#include "cgroup-setup.h"
@@ -1685,6 +1686,29 @@ static int apply_restrict_namespaces(const Unit *u, const ExecContext *c) {
return seccomp_restrict_namespaces(c->restrict_namespaces);
}
#if HAVE_LIBBPF
static bool skip_lsm_bpf_unsupported(const Unit* u, const char* msg) {
if (lsm_bpf_supported())
return false;
log_unit_debug(u, "LSM BPF not supported, skipping %s", msg);
return true;
}
static int apply_restrict_filesystems(Unit *u, const ExecContext *c) {
assert(u);
assert(c);
if (!exec_context_restrict_filesystems_set(c))
return 0;
if (skip_lsm_bpf_unsupported(u, "RestrictFileSystems="))
return 0;
return lsm_bpf_unit_restrict_filesystems(u, c->restrict_filesystems, c->restrict_filesystems_allow_list);
}
#endif
static int apply_lock_personality(const Unit* u, const ExecContext *c) {
unsigned long personality;
int r;
@@ -3813,7 +3837,7 @@ static int exec_child(
/* In case anything used libc syslog(), close this here, too */
closelog();
int keep_fds[n_fds + 2];
int keep_fds[n_fds + 3];
memcpy_safe(keep_fds, fds, n_fds * sizeof(int));
n_keep_fds = n_fds;
@@ -3823,6 +3847,24 @@ static int exec_child(
return log_unit_error_errno(unit, r, "Failed to shift fd and set FD_CLOEXEC: %m");
}
#if HAVE_LIBBPF
if (MANAGER_IS_SYSTEM(unit->manager) && lsm_bpf_supported()) {
int bpf_map_fd = -1;
bpf_map_fd = lsm_bpf_map_restrict_fs_fd(unit);
if (bpf_map_fd < 0) {
*exit_status = EXIT_FDS;
return log_unit_error_errno(unit, r, "Failed to get restrict filesystems BPF map fd: %m");
}
r = add_shifted_fd(keep_fds, ELEMENTSOF(keep_fds), &n_keep_fds, bpf_map_fd, &bpf_map_fd);
if (r < 0) {
*exit_status = EXIT_FDS;
return log_unit_error_errno(unit, r, "Failed to shift fd and set FD_CLOEXEC: %m");
}
}
#endif
r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, keep_fds, n_keep_fds);
if (r < 0) {
*exit_status = EXIT_FDS;
@@ -4682,6 +4724,15 @@ static int exec_child(
return log_unit_error_errno(unit, r, "Failed to apply system call filters: %m");
}
#endif
#if HAVE_LIBBPF
r = apply_restrict_filesystems(unit, context);
if (r < 0) {
*exit_status = EXIT_BPF;
return log_unit_error_errno(unit, r, "Failed to restrict filesystems: %m");
}
#endif
}
if (!strv_isempty(context->unset_environment)) {
@@ -4967,6 +5018,8 @@ void exec_context_done(ExecContext *c) {
c->apparmor_profile = mfree(c->apparmor_profile);
c->smack_process_label = mfree(c->smack_process_label);
c->restrict_filesystems = set_free(c->restrict_filesystems);
c->syscall_filter = hashmap_free(c->syscall_filter);
c->syscall_archs = set_free(c->syscall_archs);
c->address_families = set_free(c->address_families);
@@ -5734,6 +5787,12 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
prefix, strna(s));
}
#if HAVE_LIBBPF
if (exec_context_restrict_filesystems_set(c))
SET_FOREACH(e, c->restrict_filesystems)
fprintf(f, "%sRestrictFileSystems: %s\n", prefix, *e);
#endif
if (c->network_namespace_path)
fprintf(f,
"%sNetworkNamespacePath: %s\n",