/* Takes a value generated randomly or by hashing and turns it into a UID in the right range */
#define UID_CLAMP_INTO_RANGE(rnd) (((uid_t) (rnd) % (DYNAMIC_UID_MAX - DYNAMIC_UID_MIN + 1)) + DYNAMIC_UID_MIN)
-DEFINE_PRIVATE_TRIVIAL_REF_FUNC(DynamicUser, dynamic_user);
+DEFINE_TRIVIAL_REF_FUNC(DynamicUser, dynamic_user);
static DynamicUser* dynamic_user_free(DynamicUser *d) {
if (!d)
DynamicUser *d;
int r;
- assert(m);
+ assert(m || ret);
assert(name);
assert(storage_socket);
- r = hashmap_ensure_allocated(&m->dynamic_users, &string_hash_ops);
- if (r < 0)
- return r;
+ if (m) { /* Might be called in sd-executor with no manager object */
+ r = hashmap_ensure_allocated(&m->dynamic_users, &string_hash_ops);
+ if (r < 0)
+ return r;
+ }
d = malloc0(offsetof(DynamicUser, name) + strlen(name) + 1);
if (!d)
d->storage_socket[0] = storage_socket[0];
d->storage_socket[1] = storage_socket[1];
- r = hashmap_put(m->dynamic_users, d->name, d);
- if (r < 0) {
- free(d);
- return r;
+ if (m) { /* Might be called in sd-executor with no manager object */
+ r = hashmap_put(m->dynamic_users, d->name, d);
+ if (r < 0) {
+ free(d);
+ return r;
+ }
}
d->manager = m;
return dynamic_user_free(d);
}
-int dynamic_user_serialize(Manager *m, FILE *f, FDSet *fds) {
- DynamicUser *d;
+int dynamic_user_serialize_one(DynamicUser *d, const char *key, FILE *f, FDSet *fds) {
+ int copy0, copy1;
- assert(m);
+ assert(key);
assert(f);
assert(fds);
- /* Dump the dynamic user database into the manager serialization, to deal with daemon reloads. */
+ if (!d)
+ return 0;
- HASHMAP_FOREACH(d, m->dynamic_users) {
- int copy0, copy1;
+ if (d->storage_socket[0] < 0 || d->storage_socket[1] < 0)
+ return 0;
- copy0 = fdset_put_dup(fds, d->storage_socket[0]);
- if (copy0 < 0)
- return log_error_errno(copy0, "Failed to add dynamic user storage fd to serialization: %m");
+ copy0 = fdset_put_dup(fds, d->storage_socket[0]);
+ if (copy0 < 0)
+ return log_error_errno(copy0, "Failed to add dynamic user storage fd to serialization: %m");
- copy1 = fdset_put_dup(fds, d->storage_socket[1]);
- if (copy1 < 0)
- return log_error_errno(copy1, "Failed to add dynamic user storage fd to serialization: %m");
+ copy1 = fdset_put_dup(fds, d->storage_socket[1]);
+ if (copy1 < 0)
+ return log_error_errno(copy1, "Failed to add dynamic user storage fd to serialization: %m");
- (void) serialize_item_format(f, "dynamic-user", "%s %i %i", d->name, copy0, copy1);
- }
+ (void) serialize_item_format(f, key, "%s %i %i", d->name, copy0, copy1);
+
+ return 0;
+}
+
+int dynamic_user_serialize(Manager *m, FILE *f, FDSet *fds) {
+ DynamicUser *d;
+
+ assert(m);
+
+ /* Dump the dynamic user database into the manager serialization, to deal with daemon reloads. */
+
+ HASHMAP_FOREACH(d, m->dynamic_users)
+ (void) dynamic_user_serialize_one(d, "dynamic-user", f, fds);
return 0;
}
-void dynamic_user_deserialize_one(Manager *m, const char *value, FDSet *fds) {
+void dynamic_user_deserialize_one(Manager *m, const char *value, FDSet *fds, DynamicUser **ret) {
_cleanup_free_ char *name = NULL, *s0 = NULL, *s1 = NULL;
int r, fd0, fd1;
- assert(m);
assert(value);
assert(fds);
return;
}
- r = dynamic_user_add(m, name, (int[]) { fd0, fd1 }, NULL);
+ r = dynamic_user_add(m, name, (int[]) { fd0, fd1 }, ret);
if (r < 0) {
log_debug_errno(r, "Failed to add dynamic user: %m");
return;
(void) fdset_remove(fds, fd0);
(void) fdset_remove(fds, fd1);
+
+ if (ret) /* If the caller uses it directly, increment the refcount */
+ (*ret)->n_ref++;
}
void dynamic_user_vacuum(Manager *m, bool close_user) {
#include "execute.h"
#include "exit-status.h"
#include "fd-util.h"
+#include "fileio.h"
#include "format-util.h"
#include "glob-util.h"
#include "hexdecoct.h"
#endif
#if HAVE_LIBBPF
-static int apply_restrict_filesystems(Unit *u, const ExecContext *c) {
+static int apply_restrict_filesystems(Unit *u, const ExecContext *c, const ExecParameters *p) {
assert(u);
assert(c);
+ assert(p);
if (!exec_context_restrict_filesystems_set(c))
return 0;
- if (!u->manager->restrict_fs) {
+ if (p->bpf_outer_map_fd < 0) {
/* LSM BPF is unsupported or lsm_bpf_setup failed */
log_unit_debug(u, "LSM BPF not supported, skipping RestrictFileSystems=");
return 0;
}
- return lsm_bpf_unit_restrict_filesystems(u, c->restrict_filesystems, c->restrict_filesystems_allow_list);
+ return lsm_bpf_unit_restrict_filesystems(u, c->restrict_filesystems, p->bpf_outer_map_fd, c->restrict_filesystems_allow_list);
}
#endif
#if ENABLE_SMACK
static int setup_smack(
- const Manager *manager,
+ const ExecParameters *params,
const ExecContext *context,
int executable_fd) {
int r;
- assert(context);
+ assert(params);
assert(executable_fd >= 0);
if (context->smack_process_label) {
r = mac_smack_apply_pid(0, context->smack_process_label);
if (r < 0)
return r;
- } else if (manager->defaults.smack_process_label) {
+ } else if (params->fallback_smack_process_label) {
_cleanup_free_ char *exec_label = NULL;
r = mac_smack_read_fd(executable_fd, SMACK_ATTR_EXEC, &exec_label);
if (r < 0 && !ERRNO_IS_XATTR_ABSENT(r))
return r;
- r = mac_smack_apply_pid(0, exec_label ?: manager->defaults.smack_process_label);
+ r = mac_smack_apply_pid(0, exec_label ?: params->fallback_smack_process_label);
if (r < 0)
return r;
}
static int close_remaining_fds(
const ExecParameters *params,
const ExecRuntime *runtime,
- int user_lookup_fd,
int socket_fd,
const int *fds, size_t n_fds) {
append_socket_pair(dont_close, &n_dont_close, runtime->dynamic_creds->group->storage_socket);
}
- if (user_lookup_fd >= 0)
- dont_close[n_dont_close++] = user_lookup_fd;
+ if (params->user_lookup_fd >= 0)
+ dont_close[n_dont_close++] = params->user_lookup_fd;
return close_all_fds(dont_close, n_dont_close);
}
!strv_isempty(context->no_exec_paths);
}
+static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***l);
+static int exec_context_named_iofds(const ExecContext *c, const ExecParameters *p, int named_iofds[static 3]);
+
static int exec_child(
Unit *unit,
const ExecCommand *command,
const ExecContext *context,
- const ExecParameters *params,
+ ExecParameters *params,
ExecRuntime *runtime,
const CGroupContext *cgroup_context,
- int socket_fd,
- const int named_iofds[static 3],
- int *params_fds,
- size_t n_socket_fds,
- size_t n_storage_fds,
- char **files_env,
- int user_lookup_fd,
int *exit_status) {
_cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **joined_exec_search_path = NULL, **accum_env = NULL, **replaced_argv = NULL;
gid_t saved_gid = getgid();
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
- size_t n_fds = n_socket_fds + n_storage_fds, /* fds to pass to the child */
+ size_t n_fds, /* fds to pass to the child */
n_keep_fds; /* total number of fds not to close */
int secure_bits;
_cleanup_free_ gid_t *gids_after_pam = NULL;
int ngids_after_pam = 0;
_cleanup_free_ int *fds = NULL;
_cleanup_strv_free_ char **fdnames = NULL;
+ int socket_fd = -EBADF, named_iofds[3] = { -EBADF, -EBADF, -EBADF }, *params_fds = NULL;
+ size_t n_storage_fds = 0, n_socket_fds = 0;
assert(unit);
assert(command);
assert(command->path);
assert(!strv_isempty(command->argv));
+ if (context->std_input == EXEC_INPUT_SOCKET ||
+ context->std_output == EXEC_OUTPUT_SOCKET ||
+ context->std_error == EXEC_OUTPUT_SOCKET) {
+
+ if (params->n_socket_fds > 1)
+ return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EINVAL), "Got more than one socket.");
+
+ if (params->n_socket_fds == 0)
+ return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EINVAL), "Got no socket.");
+
+ socket_fd = params->fds[0];
+ } else {
+ params_fds = params->fds;
+ n_socket_fds = params->n_socket_fds;
+ n_storage_fds = params->n_storage_fds;
+ }
+ n_fds = n_socket_fds + n_storage_fds;
+
+ r = exec_context_named_iofds(context, params, named_iofds);
+ if (r < 0)
+ return log_unit_error_errno(unit, r, "Failed to load a named file descriptor: %m");
+
rename_process_from_path(command->path);
/* We reset exactly these signals, since they are the only ones we set to SIG_IGN in the main
}
#if HAVE_LIBBPF
- if (unit->manager->restrict_fs) {
- int 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, bpf_map_fd, "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 (params->bpf_outer_map_fd >= 0) {
+ r = add_shifted_fd(keep_fds, ELEMENTSOF(keep_fds), &n_keep_fds, params->bpf_outer_map_fd, (int *)¶ms->bpf_outer_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, user_lookup_fd, socket_fd, keep_fds, n_keep_fds);
+ r = close_remaining_fds(params, runtime, socket_fd, keep_fds, n_keep_fds);
if (r < 0) {
*exit_status = EXIT_FDS;
return log_unit_error_errno(unit, r, "Failed to close unwanted file descriptors: %m");
exec_context_tty_reset(context, params);
- if (unit_shall_confirm_spawn(unit)) {
+ if (params->shall_confirm_spawn && unit_shall_confirm_spawn(unit)) {
_cleanup_free_ char *cmdline = NULL;
cmdline = quote_command_line(command->argv, SHELL_ESCAPE_EMPTY);
return log_unit_error_errno(unit, r, "Failed to determine supplementary groups: %m");
}
- r = send_user_lookup(unit, user_lookup_fd, uid, gid);
+ r = send_user_lookup(unit, params->user_lookup_fd, uid, gid);
if (r < 0) {
*exit_status = EXIT_USER;
return log_unit_error_errno(unit, r, "Failed to send user credentials to PID1: %m");
}
- user_lookup_fd = safe_close(user_lookup_fd);
+ params->user_lookup_fd = safe_close(params->user_lookup_fd);
r = acquire_home(context, uid, &home, &home_buffer);
if (r < 0) {
joined_exec_search_path,
pass_env,
context->environment,
- files_env);
+ params->files_env);
if (!accum_env) {
*exit_status = EXIT_MEMORY;
return log_oom();
/* LSM Smack needs the capability CAP_MAC_ADMIN to change the current execution security context of the
* process. This is the latest place before dropping capabilities. Other MAC context are set later. */
if (use_smack) {
- r = setup_smack(unit->manager, context, executable_fd);
+ r = setup_smack(params, context, executable_fd);
if (r < 0 && !context->smack_process_label_ignore) {
*exit_status = EXIT_SMACK_PROCESS_LABEL;
return log_unit_error_errno(unit, r, "Failed to set SMACK process label: %m");
#endif
#if HAVE_LIBBPF
- r = apply_restrict_filesystems(unit, context);
+ r = apply_restrict_filesystems(unit, context, params);
if (r < 0) {
*exit_status = EXIT_BPF;
return log_unit_error_errno(unit, r, "Failed to restrict filesystems: %m");
return log_unit_error_errno(unit, r, "Failed to execute %s: %m", executable);
}
-static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***l);
-static int exec_context_named_iofds(const ExecContext *c, const ExecParameters *p, int named_iofds[static 3]);
int exec_spawn(Unit *unit,
ExecCommand *command,
const ExecContext *context,
- const ExecParameters *params,
+ ExecParameters *params,
ExecRuntime *runtime,
const CGroupContext *cgroup_context,
pid_t *ret) {
- int socket_fd, r, named_iofds[3] = { -1, -1, -1 }, *fds = NULL;
_cleanup_free_ char *subcgroup_path = NULL;
- _cleanup_strv_free_ char **files_env = NULL;
- size_t n_storage_fds = 0, n_socket_fds = 0;
pid_t pid;
+ int r;
assert(unit);
+ assert(unit->manager);
assert(command);
assert(context);
assert(ret);
LOG_CONTEXT_PUSH_UNIT(unit);
- if (context->std_input == EXEC_INPUT_SOCKET ||
- context->std_output == EXEC_OUTPUT_SOCKET ||
- context->std_error == EXEC_OUTPUT_SOCKET) {
-
- if (params->n_socket_fds > 1)
- return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EINVAL), "Got more than one socket.");
-
- if (params->n_socket_fds == 0)
- return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EINVAL), "Got no socket.");
-
- socket_fd = params->fds[0];
- } else {
- socket_fd = -EBADF;
- fds = params->fds;
- n_socket_fds = params->n_socket_fds;
- n_storage_fds = params->n_storage_fds;
- }
-
- r = exec_context_named_iofds(context, params, named_iofds);
- if (r < 0)
- return log_unit_error_errno(unit, r, "Failed to load a named file descriptor: %m");
-
- r = exec_context_load_environment(unit, context, &files_env);
+ r = exec_context_load_environment(unit, context, ¶ms->files_env);
if (r < 0)
return log_unit_error_errno(unit, r, "Failed to load environment files: %m");
params,
runtime,
cgroup_context,
- socket_fd,
- named_iofds,
- fds,
- n_socket_fds,
- n_storage_fds,
- files_env,
- unit->manager->user_lookup_fds[1],
&exit_status);
if (r < 0) {
void exec_context_init(ExecContext *c) {
assert(c);
+ /* When initializing a bool member to 'true', make sure to serialize in execute-serialize.c using
+ * serialize_bool() instead of serialize_bool_elide(). */
+
*c = (ExecContext) {
.umask = 0022,
.ioprio = IOPRIO_DEFAULT_CLASS_AND_PRIO,
int exec_shared_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds) {
_cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt_create = NULL;
- ExecSharedRuntime *rt;
+ ExecSharedRuntime *rt = NULL;
int r;
/* This is for the migration from old (v237 or earlier) deserialization text.
return 0;
}
- if (hashmap_ensure_allocated(&u->manager->exec_shared_runtime_by_id, &string_hash_ops) < 0)
- return log_oom();
+ if (u->manager) {
+ if (hashmap_ensure_allocated(&u->manager->exec_shared_runtime_by_id, &string_hash_ops) < 0)
+ return log_oom();
- rt = hashmap_get(u->manager->exec_shared_runtime_by_id, u->id);
+ rt = hashmap_get(u->manager->exec_shared_runtime_by_id, u->id);
+ }
if (!rt) {
if (exec_shared_runtime_allocate(&rt_create, u->id) < 0)
return log_oom();
return 0;
/* If the object is newly created, then put it to the hashmap which manages ExecSharedRuntime objects. */
- if (rt_create) {
+ if (rt_create && u->manager) {
r = hashmap_put(u->manager->exec_shared_runtime_by_id, rt_create->id, rt_create);
if (r < 0) {
log_unit_debug_errno(u, r, "Failed to put runtime parameter to manager's storage: %m");
p->environment = strv_free(p->environment);
p->fd_names = strv_free(p->fd_names);
+ p->files_env = strv_free(p->files_env);
p->fds = mfree(p->fds);
p->exec_fd = safe_close(p->exec_fd);
+ p->user_lookup_fd = safe_close(p->user_lookup_fd);
+ p->bpf_outer_map_fd = -EBADF;
}
void exec_directory_done(ExecDirectory *d) {