return context_has_address_families(c) ||
c->memory_deny_write_execute ||
c->restrict_realtime ||
+ c->restrict_suid_sgid ||
exec_context_restrict_namespaces_set(c) ||
c->protect_kernel_tunables ||
c->protect_kernel_modules ||
return seccomp_restrict_realtime();
}
+static int apply_restrict_suid_sgid(const Unit* u, const ExecContext *c) {
+ assert(u);
+ assert(c);
+
+ if (!c->restrict_suid_sgid)
+ return 0;
+
+ if (skip_seccomp_unavailable(u, "RestrictSUIDSGID="))
+ return 0;
+
+ return seccomp_restrict_suid_sgid();
+}
+
static int apply_protect_sysctl(const Unit *u, const ExecContext *c) {
assert(u);
assert(c);
}
/* Lock down the access mode (we use chmod_and_chown() to make this idempotent. We don't
- * specifiy UID/GID here, so that path_chown_recursive() can optimize things depending on the
+ * specify UID/GID here, so that path_chown_recursive() can optimize things depending on the
* current UID/GID ownership.) */
r = chmod_and_chown(pp ?: p, context->directories[type].mode, UID_INVALID, GID_INVALID);
if (r < 0)
goto fail;
- /* Then, change the ownership of the whole tree, if necessary */
- r = path_chown_recursive(pp ?: p, uid, gid);
+ /* Then, change the ownership of the whole tree, if necessary. When dynamic users are used we
+ * drop the suid/sgid bits, since we really don't want SUID/SGID files for dynamic UID/GID
+ * assignments to exist.*/
+ r = path_chown_recursive(pp ?: p, uid, gid, context->dynamic_user ? 01777 : 07777);
if (r < 0)
goto fail;
}
.source = s,
.destination = d,
.read_only = false,
+ .nosuid = context->dynamic_user, /* don't allow suid/sgid when DynamicUser= is on */
.recursive = true,
.ignore_enoent = false,
};
const ExecCommand *command,
const ExecContext *context,
const ExecParameters *params,
- const ExecRuntime *runtime) {
+ const ExecRuntime *runtime,
+ char **error_path) {
_cleanup_strv_free_ char **empty_directories = NULL;
char *tmp = NULL, *var = NULL;
needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
context->mount_flags,
- DISSECT_IMAGE_DISCARD_ON_LOOP);
+ DISSECT_IMAGE_DISCARD_ON_LOOP,
+ error_path);
bind_mount_free_many(bind_mounts, n_bind_mounts);
/* If we couldn't set up the namespace this is probably due to a missing capability. setup_namespace() reports
- * that with a special, recognizable error ENOANO. In this case, silently proceeed, but only if exclusively
+ * that with a special, recognizable error ENOANO. In this case, silently proceed, but only if exclusively
* sandboxing options were used, i.e. nothing such as RootDirectory= or BindMount= that would result in a
* completely different execution environment. */
if (r == -ENOANO) {
needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
if (needs_mount_namespace) {
- r = apply_mount_namespace(unit, command, context, params, runtime);
+ _cleanup_free_ char *error_path = NULL;
+
+ r = apply_mount_namespace(unit, command, context, params, runtime, &error_path);
if (r < 0) {
*exit_status = EXIT_NAMESPACE;
- return log_unit_error_errno(unit, r, "Failed to set up mount namespacing: %m");
+ return log_unit_error_errno(unit, r, "Failed to set up mount namespacing%s%s: %m",
+ error_path ? ": " : "", strempty(error_path));
}
}
return log_unit_error_errno(unit, r, "Failed to apply realtime restrictions: %m");
}
+ r = apply_restrict_suid_sgid(unit, context);
+ if (r < 0) {
+ *exit_status = EXIT_SECCOMP;
+ return log_unit_error_errno(unit, r, "Failed to apply SUID/SGID restrictions: %m");
+ }
+
r = apply_restrict_namespaces(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
"%sIgnoreSIGPIPE: %s\n"
"%sMemoryDenyWriteExecute: %s\n"
"%sRestrictRealtime: %s\n"
+ "%sRestrictSUIDSGID: %s\n"
"%sKeyringMode: %s\n"
"%sProtectHostname: %s\n",
prefix, c->umask,
prefix, yes_no(c->ignore_sigpipe),
prefix, yes_no(c->memory_deny_write_execute),
prefix, yes_no(c->restrict_realtime),
+ prefix, yes_no(c->restrict_suid_sgid),
prefix, exec_keyring_mode_to_string(c->keyring_mode),
prefix, yes_no(c->protect_hostname));