1
0
mirror of https://github.com/systemd/systemd.git synced 2025-08-25 13:49:55 +03:00

core: ensure execute/spawn functions can work without Unit object

When switching to serialization later, the Unit object will not be
serialized, move parameters around instead
This commit is contained in:
Luca Boccassi
2023-08-31 20:58:22 +01:00
parent 154eb43f38
commit b646fc324a
12 changed files with 585 additions and 381 deletions

View File

@ -154,20 +154,14 @@ int lsm_bpf_setup(Manager *m) {
return 0;
}
int lsm_bpf_unit_restrict_filesystems(Unit *u, const Set *filesystems, int outer_map_fd, bool allow_list) {
_cleanup_close_ int outer_map_fd_cleanup = -EBADF;
int lsm_bpf_restrict_filesystems(const Set *filesystems, uint64_t cgroup_id, int outer_map_fd, bool allow_list) {
uint32_t dummy_value = 1, zero = 0;
const char *fs;
const statfs_f_type_t *magic;
int r;
assert(filesystems);
assert(u);
assert(outer_map_fd >= 0 || u->manager);
if (u->manager && !u->manager->restrict_fs) /* Might be called in sd-executor with no manager object */
return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL),
"bpf-lsm: BPF LSM object is not installed, has setup failed?");
assert(outer_map_fd >= 0);
int inner_map_fd = compat_bpf_map_create(
BPF_MAP_TYPE_HASH,
@ -177,41 +171,35 @@ int lsm_bpf_unit_restrict_filesystems(Unit *u, const Set *filesystems, int outer
128U, /* Should be enough for all filesystem types */
NULL);
if (inner_map_fd < 0)
return log_unit_error_errno(u, errno, "bpf-lsm: Failed to create inner BPF map: %m");
return log_error_errno(errno, "bpf-lsm: Failed to create inner BPF map: %m");
if (outer_map_fd < 0) {
outer_map_fd_cleanup = outer_map_fd = sym_bpf_map__fd(u->manager->restrict_fs->maps.cgroup_hash);
if (outer_map_fd < 0)
return log_unit_error_errno(u, errno, "bpf-lsm: Failed to get BPF map fd: %m");
}
if (sym_bpf_map_update_elem(outer_map_fd, &u->cgroup_id, &inner_map_fd, BPF_ANY) != 0)
return log_unit_error_errno(u, errno, "bpf-lsm: Error populating BPF map: %m");
if (sym_bpf_map_update_elem(outer_map_fd, &cgroup_id, &inner_map_fd, BPF_ANY) != 0)
return log_error_errno(errno, "bpf-lsm: Error populating BPF map: %m");
uint32_t allow = allow_list;
/* Use key 0 to store whether this is an allow list or a deny list */
if (sym_bpf_map_update_elem(inner_map_fd, &zero, &allow, BPF_ANY) != 0)
return log_unit_error_errno(u, errno, "bpf-lsm: Error initializing map: %m");
return log_error_errno(errno, "bpf-lsm: Error initializing map: %m");
SET_FOREACH(fs, filesystems) {
r = fs_type_from_string(fs, &magic);
if (r < 0) {
log_unit_warning(u, "bpf-lsm: Invalid filesystem name '%s', ignoring.", fs);
log_warning("bpf-lsm: Invalid filesystem name '%s', ignoring.", fs);
continue;
}
log_unit_debug(u, "bpf-lsm: Restricting filesystem access to '%s'", fs);
log_debug("bpf-lsm: Restricting filesystem access to '%s'", fs);
for (int i = 0; i < FILESYSTEM_MAGIC_MAX; i++) {
if (magic[i] == 0)
break;
if (sym_bpf_map_update_elem(inner_map_fd, &magic[i], &dummy_value, BPF_ANY) != 0) {
r = log_unit_error_errno(u, errno, "bpf-lsm: Failed to update BPF map: %m");
r = log_error_errno(errno, "bpf-lsm: Failed to update BPF map: %m");
if (sym_bpf_map_delete_elem(outer_map_fd, &u->cgroup_id) != 0)
log_unit_debug_errno(u, errno, "bpf-lsm: Failed to delete cgroup entry from BPF map: %m");
if (sym_bpf_map_delete_elem(outer_map_fd, &cgroup_id) != 0)
log_debug_errno(errno, "bpf-lsm: Failed to delete cgroup entry from BPF map: %m");
return r;
}
@ -267,8 +255,8 @@ int lsm_bpf_setup(Manager *m) {
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "bpf-lsm: Failed to set up LSM BPF: %m");
}
int lsm_bpf_unit_restrict_filesystems(Unit *u, const Set *filesystems, int outer_map_fd, const bool allow_list) {
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "bpf-lsm: Failed to restrict filesystems using LSM BPF: %m");
int lsm_bpf_restrict_filesystems(const Set *filesystems, uint64_t cgroup_id, int outer_map_fd, const bool allow_list) {
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "bpf-lsm: Failed to restrict filesystems using LSM BPF: %m");
}
int lsm_bpf_cleanup(const Unit *u) {

View File

@ -16,7 +16,7 @@ typedef struct restrict_fs_bpf restrict_fs_bpf;
bool lsm_bpf_supported(bool initialize);
int lsm_bpf_setup(Manager *m);
int lsm_bpf_unit_restrict_filesystems(Unit *u, const Set *filesystems, int outer_map_fd, bool allow_list);
int lsm_bpf_restrict_filesystems(const Set *filesystems, uint64_t cgroup_id, int outer_map_fd, bool allow_list);
int lsm_bpf_cleanup(const Unit *u);
int lsm_bpf_map_restrict_fs_fd(Unit *u);
void lsm_bpf_destroy(struct restrict_fs_bpf *prog);

File diff suppressed because it is too large Load Diff

View File

@ -421,6 +421,7 @@ struct ExecParameters {
CGroupMask cgroup_supported;
const char *cgroup_path;
uint64_t cgroup_id;
char **prefix;
const char *received_credentials_directory;
@ -449,8 +450,24 @@ struct ExecParameters {
char **files_env;
int user_lookup_fd;
int bpf_outer_map_fd;
/* Used for logging in the executor functions */
char *unit_id;
sd_id128_t invocation_id;
char invocation_id_string[SD_ID128_STRING_MAX];
};
#define EXEC_PARAMETERS_INIT(_flags) \
(ExecParameters) { \
.flags = (_flags), \
.stdin_fd = -EBADF, \
.stdout_fd = -EBADF, \
.stderr_fd = -EBADF, \
.exec_fd = -EBADF, \
.bpf_outer_map_fd = -EBADF, \
.user_lookup_fd = -EBADF, \
};
#include "unit.h"
#include "dynamic-user.h"
@ -551,3 +568,103 @@ ExecDirectoryType exec_resource_type_from_string(const char *s) _pure_;
bool exec_needs_mount_namespace(const ExecContext *context, const ExecParameters *params, const ExecRuntime *runtime);
bool exec_needs_network_namespace(const ExecContext *context);
/* These logging macros do the same logging as those in unit.h, but using ExecContext and ExecParameters
* instead of the unit object, so that it can be used in the sd-executor context (where the unit object is
* not available). */
#define LOG_EXEC_ID_FIELD(ep) \
((ep)->runtime_scope == RUNTIME_SCOPE_USER ? "USER_UNIT=" : "UNIT=")
#define LOG_EXEC_ID_FIELD_FORMAT(ep) \
((ep)->runtime_scope == RUNTIME_SCOPE_USER ? "USER_UNIT=%s" : "UNIT=%s")
#define LOG_EXEC_INVOCATION_ID_FIELD(ep) \
((ep)->runtime_scope == RUNTIME_SCOPE_USER ? "USER_INVOCATION_ID=" : "INVOCATION_ID=")
#define LOG_EXEC_INVOCATION_ID_FIELD_FORMAT(ep) \
((ep)->runtime_scope == RUNTIME_SCOPE_USER ? "USER_INVOCATION_ID=%s" : "INVOCATION_ID=%s")
#define log_exec_full_errno_zerook(ec, ep, level, error, ...) \
({ \
const ExecContext *_c = (ec); \
const ExecParameters *_p = (ep); \
const int _l = (level); \
bool _do_log = !(log_get_max_level() < LOG_PRI(_l) || \
!(_c->log_level_max < 0 || \
_c->log_level_max >= LOG_PRI(_l))); \
LOG_CONTEXT_PUSH_IOV(_c->log_extra_fields, \
_c->n_log_extra_fields); \
!_do_log ? -ERRNO_VALUE(error) : \
log_object_internal(_l, error, PROJECT_FILE, \
__LINE__, __func__, \
LOG_EXEC_ID_FIELD(_p), \
_p->unit_id, \
LOG_EXEC_INVOCATION_ID_FIELD(_p), \
_p->invocation_id_string, ##__VA_ARGS__); \
})
#define log_exec_full_errno(ec, ep, level, error, ...) \
({ \
int _error = (error); \
ASSERT_NON_ZERO(_error); \
log_exec_full_errno_zerook(ec, ep, level, _error, ##__VA_ARGS__); \
})
#define log_exec_full(ec, ep, level, ...) (void) log_exec_full_errno_zerook(ec, ep, level, 0, __VA_ARGS__)
#define log_exec_debug(ec, ep, ...) log_exec_full(ec, ep, LOG_DEBUG, __VA_ARGS__)
#define log_exec_info(ec, ep, ...) log_exec_full(ec, ep, LOG_INFO, __VA_ARGS__)
#define log_exec_notice(ec, ep, ...) log_exec_full(ec, ep, LOG_NOTICE, __VA_ARGS__)
#define log_exec_warning(ec, ep, ...) log_exec_full(ec, ep, LOG_WARNING, __VA_ARGS__)
#define log_exec_error(ec, ep, ...) log_exec_full(ec, ep, LOG_ERR, __VA_ARGS__)
#define log_exec_debug_errno(ec, ep, error, ...) log_exec_full_errno(ec, ep, LOG_DEBUG, error, __VA_ARGS__)
#define log_exec_info_errno(ec, ep, error, ...) log_exec_full_errno(ec, ep, LOG_INFO, error, __VA_ARGS__)
#define log_exec_notice_errno(ec, ep, error, ...) log_exec_full_errno(ec, ep, LOG_NOTICE, error, __VA_ARGS__)
#define log_exec_warning_errno(ec, ep, error, ...) log_exec_full_errno(ec, ep, LOG_WARNING, error, __VA_ARGS__)
#define log_exec_error_errno(ec, ep, error, ...) log_exec_full_errno(ec, ep, LOG_ERR, error, __VA_ARGS__)
#define log_exec_struct_errno(ec, ep, level, error, ...) \
({ \
const ExecContext *_c = (ec); \
const ExecParameters *_p = (ep); \
const int _l = (level); \
bool _do_log = !(_c->log_level_max < 0 || \
_c->log_level_max >= LOG_PRI(_l)); \
LOG_CONTEXT_PUSH_IOV(_c->log_extra_fields, \
_c->n_log_extra_fields); \
_do_log ? \
log_struct_errno(_l, error, __VA_ARGS__, LOG_EXEC_ID_FIELD_FORMAT(_p), _p->unit_id) : \
-ERRNO_VALUE(error); \
})
#define log_exec_struct(ec, ep, level, ...) log_exec_struct_errno(ec, ep, level, 0, __VA_ARGS__)
#define log_exec_struct_iovec_errno(ec, ep, level, error, iovec, n_iovec) \
({ \
const ExecContext *_c = (ec); \
const ExecParameters *_p = (ep); \
const int _l = (level); \
bool _do_log = !(_c->log_level_max < 0 || \
_c->log_level_max >= LOG_PRI(_l)); \
LOG_CONTEXT_PUSH_IOV(_c->log_extra_fields, \
_c->n_log_extra_fields); \
_do_log ? \
log_struct_iovec_errno(_l, error, iovec, n_iovec) : \
-ERRNO_VALUE(error); \
})
#define log_exec_struct_iovec(ec, ep, level, iovec, n_iovec) log_exec_struct_iovec_errno(ec, ep, level, 0, iovec, n_iovec)
/* Like LOG_MESSAGE(), but with the unit name prefixed. */
#define LOG_EXEC_MESSAGE(ep, fmt, ...) LOG_MESSAGE("%s: " fmt, (ep)->unit_id, ##__VA_ARGS__)
#define LOG_EXEC_ID(ep) LOG_EXEC_ID_FIELD_FORMAT(ep), (ep)->unit_id
#define LOG_EXEC_INVOCATION_ID(ep) LOG_EXEC_INVOCATION_ID_FIELD_FORMAT(ep), (ep)->invocation_id_string
#define _LOG_CONTEXT_PUSH_EXEC(ec, ep, p, c) \
const ExecContext *c = (ec); \
const ExecParameters *p = (ep); \
LOG_CONTEXT_PUSH_KEY_VALUE(LOG_EXEC_ID_FIELD(p), p->unit_id); \
LOG_CONTEXT_PUSH_KEY_VALUE(LOG_EXEC_INVOCATION_ID_FIELD(p), p->invocation_id_string); \
LOG_CONTEXT_PUSH_IOV(c->log_extra_fields, c->n_log_extra_fields)
#define LOG_CONTEXT_PUSH_EXEC(ec, ep) \
_LOG_CONTEXT_PUSH_EXEC(ec, ep, UNIQ_T(p, UNIQ), UNIQ_T(c, UNIQ))

View File

@ -144,6 +144,15 @@ static usec_t manager_watch_jobs_next_time(Manager *m) {
return usec_add(now(CLOCK_MONOTONIC), timeout);
}
static bool manager_is_confirm_spawn_disabled(Manager *m) {
assert(m);
if (!m->confirm_spawn)
return true;
return access("/run/systemd/confirm_spawn_disabled", F_OK) >= 0;
}
static void manager_watch_jobs_in_progress(Manager *m) {
usec_t next;
int r;
@ -4430,13 +4439,6 @@ void manager_disable_confirm_spawn(void) {
(void) touch("/run/systemd/confirm_spawn_disabled");
}
bool manager_is_confirm_spawn_disabled(Manager *m) {
if (!m->confirm_spawn)
return true;
return access("/run/systemd/confirm_spawn_disabled", F_OK) >= 0;
}
static bool manager_should_show_status(Manager *m, StatusType type) {
assert(m);

View File

@ -616,7 +616,6 @@ const char *manager_state_to_string(ManagerState m) _const_;
ManagerState manager_state_from_string(const char *s) _pure_;
const char *manager_get_confirm_spawn(Manager *m);
bool manager_is_confirm_spawn_disabled(Manager *m);
void manager_disable_confirm_spawn(void);
const char *manager_timestamp_to_string(ManagerTimestamp m) _const_;

View File

@ -889,15 +889,8 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
static int mount_spawn(Mount *m, ExecCommand *c, PidRef *ret_pid) {
_cleanup_(exec_params_clear) ExecParameters exec_params = {
.flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
.stdin_fd = -EBADF,
.stdout_fd = -EBADF,
.stderr_fd = -EBADF,
.exec_fd = -EBADF,
.bpf_outer_map_fd = -EBADF,
.user_lookup_fd = -EBADF,
};
_cleanup_(exec_params_clear) ExecParameters exec_params = EXEC_PARAMETERS_INIT(
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
pid_t pid;
int r;

View File

@ -1602,15 +1602,7 @@ static int service_spawn_internal(
ExecFlags flags,
PidRef *ret_pid) {
_cleanup_(exec_params_clear) ExecParameters exec_params = {
.flags = flags,
.stdin_fd = -EBADF,
.stdout_fd = -EBADF,
.stderr_fd = -EBADF,
.exec_fd = -EBADF,
.bpf_outer_map_fd = -EBADF,
.user_lookup_fd = -EBADF,
};
_cleanup_(exec_params_clear) ExecParameters exec_params = EXEC_PARAMETERS_INIT(flags);
_cleanup_(sd_event_source_unrefp) sd_event_source *exec_fd_source = NULL;
_cleanup_strv_free_ char **final_env = NULL, **our_env = NULL;
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;

View File

@ -1913,15 +1913,8 @@ static int socket_coldplug(Unit *u) {
static int socket_spawn(Socket *s, ExecCommand *c, PidRef *ret_pid) {
_cleanup_(exec_params_clear) ExecParameters exec_params = {
.flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
.stdin_fd = -EBADF,
.stdout_fd = -EBADF,
.stderr_fd = -EBADF,
.exec_fd = -EBADF,
.bpf_outer_map_fd = -EBADF,
.user_lookup_fd = -EBADF,
};
_cleanup_(exec_params_clear) ExecParameters exec_params = EXEC_PARAMETERS_INIT(
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
pid_t pid;
int r;

View File

@ -632,15 +632,8 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) {
static int swap_spawn(Swap *s, ExecCommand *c, PidRef *ret_pid) {
_cleanup_(exec_params_clear) ExecParameters exec_params = {
.flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
.stdin_fd = -EBADF,
.stdout_fd = -EBADF,
.stderr_fd = -EBADF,
.exec_fd = -EBADF,
.bpf_outer_map_fd = -EBADF,
.user_lookup_fd = -EBADF,
};
_cleanup_(exec_params_clear) ExecParameters exec_params = EXEC_PARAMETERS_INIT(
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
pid_t pid;
int r;

View File

@ -1854,18 +1854,6 @@ int unit_test_start_limit(Unit *u) {
return -ECANCELED;
}
bool unit_shall_confirm_spawn(Unit *u) {
assert(u);
if (manager_is_confirm_spawn_disabled(u->manager))
return false;
/* For some reasons units remaining in the same process group
* as PID 1 fail to acquire the console even if it's not used
* by any process. So skip the confirmation question for them. */
return !unit_get_exec_context(u)->same_pgrp;
}
static bool unit_verify_deps(Unit *u) {
Unit *other;
@ -5405,9 +5393,14 @@ int unit_set_exec_params(Unit *u, ExecParameters *p) {
p->bpf_outer_map_fd = fd;
}
p->user_lookup_fd = fcntl(u->manager->user_lookup_fds[1], F_DUPFD_CLOEXEC, 3);
if (p->user_lookup_fd < 0)
return -errno;
p->user_lookup_fd = u->manager->user_lookup_fds[1];
p->cgroup_id = u->cgroup_id;
p->invocation_id = u->invocation_id;
sd_id128_to_string(p->invocation_id, p->invocation_id_string);
p->unit_id = strdup(u->id);
if (!p->unit_id)
return -ENOMEM;
return 0;
}

View File

@ -1024,8 +1024,6 @@ void unit_notify_user_lookup(Unit *u, uid_t uid, gid_t gid);
int unit_set_invocation_id(Unit *u, sd_id128_t id);
int unit_acquire_invocation_id(Unit *u);
bool unit_shall_confirm_spawn(Unit *u);
int unit_set_exec_params(Unit *s, ExecParameters *p);
int unit_fork_helper_process(Unit *u, const char *name, PidRef *ret);