summaryrefslogtreecommitdiff
path: root/src/core/execute.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/execute.c')
-rw-r--r--src/core/execute.c548
1 files changed, 193 insertions, 355 deletions
diff --git a/src/core/execute.c b/src/core/execute.c
index 4ff6f4ebd0..06a291fd39 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1259,6 +1259,41 @@ static void rename_process_from_path(const char *path) {
rename_process(process_name);
}
+static bool context_has_address_families(const ExecContext *c) {
+ assert(c);
+
+ return c->address_families_whitelist ||
+ !set_isempty(c->address_families);
+}
+
+static bool context_has_syscall_filters(const ExecContext *c) {
+ assert(c);
+
+ return c->syscall_whitelist ||
+ !set_isempty(c->syscall_filter);
+}
+
+static bool context_has_no_new_privileges(const ExecContext *c) {
+ assert(c);
+
+ if (c->no_new_privileges)
+ return true;
+
+ if (have_effective_cap(CAP_SYS_ADMIN)) /* if we are privileged, we don't need NNP */
+ return false;
+
+ /* We need NNP if we have any form of seccomp and are unprivileged */
+ return context_has_address_families(c) ||
+ c->memory_deny_write_execute ||
+ c->restrict_realtime ||
+ exec_context_restrict_namespaces_set(c) ||
+ c->protect_kernel_tunables ||
+ c->protect_kernel_modules ||
+ c->private_devices ||
+ context_has_syscall_filters(c) ||
+ !set_isempty(c->syscall_archs);
+}
+
#ifdef HAVE_SECCOMP
static bool skip_seccomp_unavailable(const Unit* u, const char* msg) {
@@ -1272,344 +1307,131 @@ static bool skip_seccomp_unavailable(const Unit* u, const char* msg) {
return true;
}
-static int apply_seccomp(const Unit* u, const ExecContext *c) {
- uint32_t negative_action, action;
- scmp_filter_ctx seccomp;
- Iterator i;
- void *id;
- int r;
+static int apply_syscall_filter(const Unit* u, const ExecContext *c) {
+ uint32_t negative_action, default_action, action;
+ assert(u);
assert(c);
- if (skip_seccomp_unavailable(u, "syscall filtering"))
+ if (!context_has_syscall_filters(c))
return 0;
- negative_action = c->syscall_errno == 0 ? SCMP_ACT_KILL : SCMP_ACT_ERRNO(c->syscall_errno);
-
- seccomp = seccomp_init(c->syscall_whitelist ? negative_action : SCMP_ACT_ALLOW);
- if (!seccomp)
- return -ENOMEM;
-
- if (c->syscall_archs) {
+ if (skip_seccomp_unavailable(u, "SystemCallFilter="))
+ return 0;
- SET_FOREACH(id, c->syscall_archs, i) {
- r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1);
- if (r == -EEXIST)
- continue;
- if (r < 0)
- goto finish;
- }
+ negative_action = c->syscall_errno == 0 ? SCMP_ACT_KILL : SCMP_ACT_ERRNO(c->syscall_errno);
+ if (c->syscall_whitelist) {
+ default_action = negative_action;
+ action = SCMP_ACT_ALLOW;
} else {
- r = seccomp_add_secondary_archs(seccomp);
- if (r < 0)
- goto finish;
+ default_action = SCMP_ACT_ALLOW;
+ action = negative_action;
}
- action = c->syscall_whitelist ? SCMP_ACT_ALLOW : negative_action;
- SET_FOREACH(id, c->syscall_filter, i) {
- r = seccomp_rule_add(seccomp, action, PTR_TO_INT(id) - 1, 0);
- if (r < 0)
- goto finish;
- }
-
- r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
- if (r < 0)
- goto finish;
-
- r = seccomp_load(seccomp);
-
-finish:
- seccomp_release(seccomp);
- return r;
+ return seccomp_load_syscall_filter_set_raw(default_action, c->syscall_filter, action);
}
-static int apply_address_families(const Unit* u, const ExecContext *c) {
- scmp_filter_ctx seccomp;
- Iterator i;
- int r;
-
+static int apply_syscall_archs(const Unit *u, const ExecContext *c) {
+ assert(u);
assert(c);
- if (skip_seccomp_unavailable(u, "RestrictAddressFamilies="))
+ if (set_isempty(c->syscall_archs))
return 0;
- r = seccomp_init_conservative(&seccomp, SCMP_ACT_ALLOW);
- if (r < 0)
- return r;
-
- if (c->address_families_whitelist) {
- int af, first = 0, last = 0;
- void *afp;
-
- /* If this is a whitelist, we first block the address
- * families that are out of range and then everything
- * that is not in the set. First, we find the lowest
- * and highest address family in the set. */
-
- SET_FOREACH(afp, c->address_families, i) {
- af = PTR_TO_INT(afp);
-
- if (af <= 0 || af >= af_max())
- continue;
-
- if (first == 0 || af < first)
- first = af;
-
- if (last == 0 || af > last)
- last = af;
- }
-
- assert((first == 0) == (last == 0));
-
- if (first == 0) {
-
- /* No entries in the valid range, block everything */
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPROTONOSUPPORT),
- SCMP_SYS(socket),
- 0);
- if (r < 0)
- goto finish;
-
- } else {
+ if (skip_seccomp_unavailable(u, "SystemCallArchitectures="))
+ return 0;
- /* Block everything below the first entry */
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPROTONOSUPPORT),
- SCMP_SYS(socket),
- 1,
- SCMP_A0(SCMP_CMP_LT, first));
- if (r < 0)
- goto finish;
-
- /* Block everything above the last entry */
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPROTONOSUPPORT),
- SCMP_SYS(socket),
- 1,
- SCMP_A0(SCMP_CMP_GT, last));
- if (r < 0)
- goto finish;
-
- /* Block everything between the first and last
- * entry */
- for (af = 1; af < af_max(); af++) {
-
- if (set_contains(c->address_families, INT_TO_PTR(af)))
- continue;
+ return seccomp_restrict_archs(c->syscall_archs);
+}
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPROTONOSUPPORT),
- SCMP_SYS(socket),
- 1,
- SCMP_A0(SCMP_CMP_EQ, af));
- if (r < 0)
- goto finish;
- }
- }
+static int apply_address_families(const Unit* u, const ExecContext *c) {
+ assert(u);
+ assert(c);
- } else {
- void *af;
-
- /* If this is a blacklist, then generate one rule for
- * each address family that are then combined in OR
- * checks. */
-
- SET_FOREACH(af, c->address_families, i) {
-
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPROTONOSUPPORT),
- SCMP_SYS(socket),
- 1,
- SCMP_A0(SCMP_CMP_EQ, PTR_TO_INT(af)));
- if (r < 0)
- goto finish;
- }
- }
+ if (!context_has_address_families(c))
+ return 0;
- r = seccomp_load(seccomp);
+ if (skip_seccomp_unavailable(u, "RestrictAddressFamilies="))
+ return 0;
-finish:
- seccomp_release(seccomp);
- return r;
+ return seccomp_restrict_address_families(c->address_families, c->address_families_whitelist);
}
static int apply_memory_deny_write_execute(const Unit* u, const ExecContext *c) {
- scmp_filter_ctx seccomp;
- int r;
-
+ assert(u);
assert(c);
- if (skip_seccomp_unavailable(u, "MemoryDenyWriteExecute="))
+ if (!c->memory_deny_write_execute)
return 0;
- r = seccomp_init_conservative(&seccomp, SCMP_ACT_ALLOW);
- if (r < 0)
- return r;
-
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPERM),
- SCMP_SYS(mmap),
- 1,
- SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC|PROT_WRITE, PROT_EXEC|PROT_WRITE));
- if (r < 0)
- goto finish;
-
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPERM),
- SCMP_SYS(mprotect),
- 1,
- SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC, PROT_EXEC));
- if (r < 0)
- goto finish;
-
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPERM),
- SCMP_SYS(shmat),
- 1,
- SCMP_A2(SCMP_CMP_MASKED_EQ, SHM_EXEC, SHM_EXEC));
- if (r < 0)
- goto finish;
-
- r = seccomp_load(seccomp);
+ if (skip_seccomp_unavailable(u, "MemoryDenyWriteExecute="))
+ return 0;
-finish:
- seccomp_release(seccomp);
- return r;
+ return seccomp_memory_deny_write_execute();
}
static int apply_restrict_realtime(const Unit* u, const ExecContext *c) {
- static const int permitted_policies[] = {
- SCHED_OTHER,
- SCHED_BATCH,
- SCHED_IDLE,
- };
-
- scmp_filter_ctx seccomp;
- unsigned i;
- int r, p, max_policy = 0;
-
+ assert(u);
assert(c);
- if (skip_seccomp_unavailable(u, "RestrictRealtime="))
+ if (!c->restrict_realtime)
return 0;
- r = seccomp_init_conservative(&seccomp, SCMP_ACT_ALLOW);
- if (r < 0)
- return r;
-
- /* Determine the highest policy constant we want to allow */
- for (i = 0; i < ELEMENTSOF(permitted_policies); i++)
- if (permitted_policies[i] > max_policy)
- max_policy = permitted_policies[i];
-
- /* Go through all policies with lower values than that, and block them -- unless they appear in the
- * whitelist. */
- for (p = 0; p < max_policy; p++) {
- bool good = false;
-
- /* Check if this is in the whitelist. */
- for (i = 0; i < ELEMENTSOF(permitted_policies); i++)
- if (permitted_policies[i] == p) {
- good = true;
- break;
- }
-
- if (good)
- continue;
-
- /* Deny this policy */
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPERM),
- SCMP_SYS(sched_setscheduler),
- 1,
- SCMP_A1(SCMP_CMP_EQ, p));
- if (r < 0)
- goto finish;
- }
-
- /* Blacklist all other policies, i.e. the ones with higher values. Note that all comparisons are unsigned here,
- * hence no need no check for < 0 values. */
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPERM),
- SCMP_SYS(sched_setscheduler),
- 1,
- SCMP_A1(SCMP_CMP_GT, max_policy));
- if (r < 0)
- goto finish;
-
- r = seccomp_load(seccomp);
+ if (skip_seccomp_unavailable(u, "RestrictRealtime="))
+ return 0;
-finish:
- seccomp_release(seccomp);
- return r;
+ return seccomp_restrict_realtime();
}
static int apply_protect_sysctl(const Unit *u, const ExecContext *c) {
- scmp_filter_ctx seccomp;
- int r;
-
+ assert(u);
assert(c);
/* Turn off the legacy sysctl() system call. Many distributions turn this off while building the kernel, but
* let's protect even those systems where this is left on in the kernel. */
- if (skip_seccomp_unavailable(u, "ProtectKernelTunables="))
+ if (!c->protect_kernel_tunables)
return 0;
- r = seccomp_init_conservative(&seccomp, SCMP_ACT_ALLOW);
- if (r < 0)
- return r;
-
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPERM),
- SCMP_SYS(_sysctl),
- 0);
- if (r < 0)
- goto finish;
-
- r = seccomp_load(seccomp);
+ if (skip_seccomp_unavailable(u, "ProtectKernelTunables="))
+ return 0;
-finish:
- seccomp_release(seccomp);
- return r;
+ return seccomp_protect_sysctl();
}
static int apply_protect_kernel_modules(const Unit *u, const ExecContext *c) {
+ assert(u);
assert(c);
/* Turn off module syscalls on ProtectKernelModules=yes */
+ if (!c->protect_kernel_modules)
+ return 0;
+
if (skip_seccomp_unavailable(u, "ProtectKernelModules="))
return 0;
- return seccomp_load_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_MODULE, SCMP_ACT_ERRNO(EPERM));
+ return seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_MODULE, SCMP_ACT_ERRNO(EPERM));
}
static int apply_private_devices(const Unit *u, const ExecContext *c) {
+ assert(u);
assert(c);
/* If PrivateDevices= is set, also turn off iopl and all @raw-io syscalls. */
+ if (!c->private_devices)
+ return 0;
+
if (skip_seccomp_unavailable(u, "PrivateDevices="))
return 0;
- return seccomp_load_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_RAW_IO, SCMP_ACT_ERRNO(EPERM));
+ return seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_RAW_IO, SCMP_ACT_ERRNO(EPERM));
}
static int apply_restrict_namespaces(Unit *u, const ExecContext *c) {
+ assert(u);
assert(c);
if (!exec_context_restrict_namespaces_set(c))
@@ -2310,41 +2132,6 @@ static int close_remaining_fds(
return close_all_fds(dont_close, n_dont_close);
}
-static bool context_has_address_families(const ExecContext *c) {
- assert(c);
-
- return c->address_families_whitelist ||
- !set_isempty(c->address_families);
-}
-
-static bool context_has_syscall_filters(const ExecContext *c) {
- assert(c);
-
- return c->syscall_whitelist ||
- !set_isempty(c->syscall_filter) ||
- !set_isempty(c->syscall_archs);
-}
-
-static bool context_has_no_new_privileges(const ExecContext *c) {
- assert(c);
-
- if (c->no_new_privileges)
- return true;
-
- if (have_effective_cap(CAP_SYS_ADMIN)) /* if we are privileged, we don't need NNP */
- return false;
-
- /* We need NNP if we have any form of seccomp and are unprivileged */
- return context_has_address_families(c) ||
- c->memory_deny_write_execute ||
- c->restrict_realtime ||
- exec_context_restrict_namespaces_set(c) ||
- c->protect_kernel_tunables ||
- c->protect_kernel_modules ||
- c->private_devices ||
- context_has_syscall_filters(c);
-}
-
static int send_user_lookup(
Unit *unit,
int user_lookup_fd,
@@ -2386,7 +2173,8 @@ static int exec_child(
int *fds, unsigned n_fds,
char **files_env,
int user_lookup_fd,
- int *exit_status) {
+ int *exit_status,
+ char **error_message) {
_cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL;
_cleanup_free_ char *mac_selinux_context_net = NULL;
@@ -2405,6 +2193,9 @@ static int exec_child(
assert(context);
assert(params);
assert(exit_status);
+ assert(error_message);
+ /* We don't always set error_message, hence it must be initialized */
+ assert(*error_message == NULL);
rename_process_from_path(command->path);
@@ -2422,6 +2213,8 @@ static int exec_child(
r = reset_signal_mask();
if (r < 0) {
*exit_status = EXIT_SIGNAL_MASK;
+ *error_message = strdup("Failed to reset signal mask");
+ /* If strdup fails, here and below, we will just print the generic error message. */
return r;
}
@@ -2437,6 +2230,7 @@ static int exec_child(
r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_FDS;
+ *error_message = strdup("Failed to close remaining fds");
return r;
}
@@ -2465,6 +2259,7 @@ static int exec_child(
return 0;
}
*exit_status = EXIT_CONFIRM;
+ *error_message = strdup("Execution cancelled");
return -ECANCELED;
}
}
@@ -2474,17 +2269,27 @@ static int exec_child(
/* Make sure we bypass our own NSS module for any NSS checks */
if (putenv((char*) "SYSTEMD_NSS_DYNAMIC_BYPASS=1") != 0) {
*exit_status = EXIT_USER;
+ *error_message = strdup("Failed to update environment");
return -errno;
}
r = dynamic_creds_realize(dcreds, &uid, &gid);
if (r < 0) {
*exit_status = EXIT_USER;
+ *error_message = strdup("Failed to update dynamic user credentials");
return r;
}
- if (!uid_is_valid(uid) || !gid_is_valid(gid)) {
+ if (!uid_is_valid(uid)) {
*exit_status = EXIT_USER;
+ (void) asprintf(error_message, "UID validation failed for \""UID_FMT"\"", uid);
+ /* If asprintf fails, here and below, we will just print the generic error message. */
+ return -ESRCH;
+ }
+
+ if (!gid_is_valid(gid)) {
+ *exit_status = EXIT_USER;
+ (void) asprintf(error_message, "GID validation failed for \""GID_FMT"\"", gid);
return -ESRCH;
}
@@ -2495,12 +2300,14 @@ static int exec_child(
r = get_fixed_user(context, &username, &uid, &gid, &home, &shell);
if (r < 0) {
*exit_status = EXIT_USER;
+ *error_message = strdup("Failed to determine user credentials");
return r;
}
r = get_fixed_group(context, &groupname, &gid);
if (r < 0) {
*exit_status = EXIT_GROUP;
+ *error_message = strdup("Failed to determine group credentials");
return r;
}
}
@@ -2510,12 +2317,14 @@ static int exec_child(
&supplementary_gids, &ngids);
if (r < 0) {
*exit_status = EXIT_GROUP;
+ *error_message = strdup("Failed to determine supplementary groups");
return r;
}
r = send_user_lookup(unit, user_lookup_fd, uid, gid);
if (r < 0) {
*exit_status = EXIT_USER;
+ *error_message = strdup("Failed to send user credentials to PID1");
return r;
}
@@ -2529,18 +2338,21 @@ static int exec_child(
r = setup_input(context, params, socket_fd, named_iofds);
if (r < 0) {
*exit_status = EXIT_STDIN;
+ *error_message = strdup("Failed to set up stdin");
return r;
}
r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, named_iofds, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
if (r < 0) {
*exit_status = EXIT_STDOUT;
+ *error_message = strdup("Failed to set up stdout");
return r;
}
r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, named_iofds, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
if (r < 0) {
*exit_status = EXIT_STDERR;
+ *error_message = strdup("Failed to set up stderr");
return r;
}
@@ -2548,6 +2360,7 @@ static int exec_child(
r = cg_attach_everywhere(params->cgroup_supported, params->cgroup_path, 0, NULL, NULL);
if (r < 0) {
*exit_status = EXIT_CGROUP;
+ (void) asprintf(error_message, "Failed to attach to cgroup %s", params->cgroup_path);
return r;
}
}
@@ -2568,6 +2381,7 @@ static int exec_child(
log_close();
} else if (r < 0) {
*exit_status = EXIT_OOM_ADJUST;
+ *error_message = strdup("Failed to write /proc/self/oom_score_adj");
return -errno;
}
}
@@ -2812,6 +2626,7 @@ static int exec_child(
r = capability_bounding_set_drop(context->capability_bounding_set, false);
if (r < 0) {
*exit_status = EXIT_CAPABILITIES;
+ *error_message = strdup("Failed to drop capabilities");
return r;
}
}
@@ -2822,6 +2637,7 @@ static int exec_child(
r = capability_ambient_set_apply(context->capability_ambient_set, true);
if (r < 0) {
*exit_status = EXIT_CAPABILITIES;
+ *error_message = strdup("Failed to apply ambient capabilities (before UID change)");
return r;
}
}
@@ -2830,6 +2646,7 @@ static int exec_child(
r = enforce_user(context, uid);
if (r < 0) {
*exit_status = EXIT_USER;
+ (void) asprintf(error_message, "Failed to change UID to "UID_FMT, uid);
return r;
}
if (context->capability_ambient_set != 0) {
@@ -2838,6 +2655,7 @@ static int exec_child(
r = capability_ambient_set_apply(context->capability_ambient_set, false);
if (r < 0) {
*exit_status = EXIT_CAPABILITIES;
+ *error_message = strdup("Failed to apply ambient capabilities (after UID change)");
return r;
}
@@ -2865,6 +2683,7 @@ static int exec_child(
r = setexeccon(exec_context);
if (r < 0) {
*exit_status = EXIT_SELINUX_CONTEXT;
+ (void) asprintf(error_message, "Failed to set SELinux context to %s", exec_context);
return r;
}
}
@@ -2874,6 +2693,7 @@ static int exec_child(
r = setup_smack(context, command);
if (r < 0) {
*exit_status = EXIT_SMACK_PROCESS_LABEL;
+ *error_message = strdup("Failed to set SMACK process label");
return r;
}
@@ -2882,6 +2702,9 @@ static int exec_child(
r = aa_change_onexec(context->apparmor_profile);
if (r < 0 && !context->apparmor_profile_ignore) {
*exit_status = EXIT_APPARMOR_PROFILE;
+ (void) asprintf(error_message,
+ "Failed to prepare AppArmor profile change to %s",
+ context->apparmor_profile);
return -errno;
}
}
@@ -2894,78 +2717,81 @@ static int exec_child(
if (prctl(PR_GET_SECUREBITS) != secure_bits)
if (prctl(PR_SET_SECUREBITS, secure_bits) < 0) {
*exit_status = EXIT_SECUREBITS;
+ *error_message = strdup("Failed to set secure bits");
return -errno;
}
if (context_has_no_new_privileges(context))
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
*exit_status = EXIT_NO_NEW_PRIVILEGES;
+ *error_message = strdup("Failed to disable new privileges");
return -errno;
}
#ifdef HAVE_SECCOMP
- if (context_has_address_families(context)) {
- r = apply_address_families(unit, context);
- if (r < 0) {
- *exit_status = EXIT_ADDRESS_FAMILIES;
- return r;
- }
+ r = apply_address_families(unit, context);
+ if (r < 0) {
+ *exit_status = EXIT_ADDRESS_FAMILIES;
+ *error_message = strdup("Failed to restrict address families");
+ return r;
}
- if (context->memory_deny_write_execute) {
- r = apply_memory_deny_write_execute(unit, context);
- if (r < 0) {
- *exit_status = EXIT_SECCOMP;
- return r;
- }
+ r = apply_memory_deny_write_execute(unit, context);
+ if (r < 0) {
+ *exit_status = EXIT_SECCOMP;
+ *error_message = strdup("Failed to disable writing to executable memory");
+ return r;
}
- if (context->restrict_realtime) {
- r = apply_restrict_realtime(unit, context);
- if (r < 0) {
- *exit_status = EXIT_SECCOMP;
- return r;
- }
+ r = apply_restrict_realtime(unit, context);
+ if (r < 0) {
+ *exit_status = EXIT_SECCOMP;
+ *error_message = strdup("Failed to apply realtime restrictions");
+ return r;
}
r = apply_restrict_namespaces(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
+ *error_message = strdup("Failed to apply namespace restrictions");
return r;
}
- if (context->protect_kernel_tunables) {
- r = apply_protect_sysctl(unit, context);
- if (r < 0) {
- *exit_status = EXIT_SECCOMP;
- return r;
- }
+ r = apply_protect_sysctl(unit, context);
+ if (r < 0) {
+ *exit_status = EXIT_SECCOMP;
+ *error_message = strdup("Failed to apply sysctl restrictions");
+ return r;
}
- if (context->protect_kernel_modules) {
- r = apply_protect_kernel_modules(unit, context);
- if (r < 0) {
- *exit_status = EXIT_SECCOMP;
- return r;
- }
+ r = apply_protect_kernel_modules(unit, context);
+ if (r < 0) {
+ *exit_status = EXIT_SECCOMP;
+ *error_message = strdup("Failed to apply module loading restrictions");
+ return r;
}
- if (context->private_devices) {
- r = apply_private_devices(unit, context);
- if (r < 0) {
- *exit_status = EXIT_SECCOMP;
- return r;
- }
+ r = apply_private_devices(unit, context);
+ if (r < 0) {
+ *exit_status = EXIT_SECCOMP;
+ *error_message = strdup("Failed to set up private devices");
+ return r;
+ }
+
+ r = apply_syscall_archs(unit, context);
+ if (r < 0) {
+ *exit_status = EXIT_SECCOMP;
+ *error_message = strdup("Failed to apply syscall architecture restrictions");
+ return r;
}
/* This really should remain the last step before the execve(), to make sure our own code is unaffected
* by the filter as little as possible. */
- if (context_has_syscall_filters(context)) {
- r = apply_seccomp(unit, context);
- if (r < 0) {
- *exit_status = EXIT_SECCOMP;
- return r;
- }
+ r = apply_syscall_filter(unit, context);
+ if (r < 0) {
+ *exit_status = EXIT_SECCOMP;
+ *error_message = strdup("Failed to apply syscall filters");
+ return r;
}
#endif
}
@@ -2973,6 +2799,7 @@ static int exec_child(
final_argv = replace_env_argv(argv, accum_env);
if (!final_argv) {
*exit_status = EXIT_MEMORY;
+ *error_message = strdup("Failed to prepare process arguments");
return -ENOMEM;
}
@@ -3059,6 +2886,7 @@ int exec_spawn(Unit *unit,
if (pid == 0) {
int exit_status;
+ _cleanup_free_ char *error_message = NULL;
r = exec_child(unit,
command,
@@ -3072,17 +2900,27 @@ int exec_spawn(Unit *unit,
fds, n_fds,
files_env,
unit->manager->user_lookup_fds[1],
- &exit_status);
+ &exit_status,
+ &error_message);
if (r < 0) {
log_open();
- log_struct_errno(LOG_ERR, r,
- LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED),
- LOG_UNIT_ID(unit),
- LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",
- exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),
- command->path),
- "EXECUTABLE=%s", command->path,
- NULL);
+ if (error_message)
+ log_struct_errno(LOG_ERR, r,
+ LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED),
+ LOG_UNIT_ID(unit),
+ LOG_UNIT_MESSAGE(unit, "%s: %m",
+ error_message),
+ "EXECUTABLE=%s", command->path,
+ NULL);
+ else
+ log_struct_errno(LOG_ERR, r,
+ LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED),
+ LOG_UNIT_ID(unit),
+ LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",
+ exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),
+ command->path),
+ "EXECUTABLE=%s", command->path,
+ NULL);
}
_exit(exit_status);