mirror of
https://github.com/systemd/systemd.git
synced 2025-03-31 14:50:15 +03:00
Merge pull request #6832 from poettering/keyring-mode
Add KeyringMode unit property to fix cryptsetup key caching
This commit is contained in:
commit
3d7d3cbbda
@ -1720,6 +1720,26 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
|
||||
<varname>NoNewPrivileges=yes</varname> is implied.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>KeyringMode=</varname></term>
|
||||
|
||||
<listitem><para>Controls how the kernel session keyring is set up for the service (see <citerefentry
|
||||
project='man-pages'><refentrytitle>session-keyring</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
|
||||
details on the session keyring). Takes one of <option>inherit</option>, <option>private</option>,
|
||||
<option>shared</option>. If set to <option>inherit</option> no special keyring setup is done, and the kernel's
|
||||
default behaviour is applied. If <option>private</option> is used a new session keyring is allocated when a
|
||||
service process is invoked, and it is not linked up with any user keyring. This is the recommended setting for
|
||||
system services, as this ensures that multiple services running under the same system user ID (in particular
|
||||
the root user) do not share their key material among each other. If <option>shared</option> is used a new
|
||||
session keyring is allocated as for <option>private</option>, but the user keyring of the user configured with
|
||||
<varname>User=</varname> is linked into it, so that keys assigned to the user may be requested by the unit's
|
||||
processes. In this modes multiple units running processes under the same user ID may share key material. Unless
|
||||
<option>inherit</option> is selected the unique invocation ID for the unit (see below) is added as a protected
|
||||
key by the name <literal>invocation_id</literal> to the newly created session keyring. Defaults to
|
||||
<option>private</option> for the system service manager and to <option>inherit</option> for the user service
|
||||
manager.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RuntimeDirectory=</varname></term>
|
||||
|
||||
|
@ -1128,6 +1128,10 @@ typedef int32_t key_serial_t;
|
||||
#define KEYCTL_DESCRIBE 6
|
||||
#endif
|
||||
|
||||
#ifndef KEYCTL_LINK
|
||||
#define KEYCTL_LINK 8
|
||||
#endif
|
||||
|
||||
#ifndef KEYCTL_READ
|
||||
#define KEYCTL_READ 11
|
||||
#endif
|
||||
|
@ -53,12 +53,11 @@
|
||||
#include "utf8.h"
|
||||
|
||||
BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
|
||||
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
|
||||
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode);
|
||||
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_preserve_mode, exec_preserve_mode, ExecPreserveMode);
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode);
|
||||
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_home, protect_home, ProtectHome);
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_system, protect_system, ProtectSystem);
|
||||
@ -873,6 +872,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||
SD_BUS_PROPERTY("BindPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("BindReadOnlyPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("MountAPIVFS", "b", bus_property_get_bool, offsetof(ExecContext, mount_apivfs), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("KeyringMode", "s", property_get_exec_keyring_mode, offsetof(ExecContext, keyring_mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
|
||||
/* Obsolete/redundant properties: */
|
||||
SD_BUS_PROPERTY("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
|
||||
@ -2139,6 +2139,27 @@ int bus_exec_context_set_transient_property(
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "KeyringMode")) {
|
||||
|
||||
const char *s;
|
||||
ExecKeyringMode m;
|
||||
|
||||
r = sd_bus_message_read(message, "s", &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
m = exec_keyring_mode_from_string(s);
|
||||
if (m < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid key ring mode");
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
c->keyring_mode = m;
|
||||
|
||||
unit_write_drop_in_private_format(u, mode, name, "KeyringMode=%s", exec_keyring_mode_to_string(m));
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "RuntimeDirectoryPreserve")) {
|
||||
const char *s;
|
||||
ExecPreserveMode m;
|
||||
|
@ -2163,10 +2163,17 @@ static int apply_working_directory(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_keyring(Unit *u, const ExecParameters *p, uid_t uid, gid_t gid) {
|
||||
static int setup_keyring(
|
||||
Unit *u,
|
||||
const ExecContext *context,
|
||||
const ExecParameters *p,
|
||||
uid_t uid, gid_t gid) {
|
||||
|
||||
key_serial_t keyring;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(context);
|
||||
assert(p);
|
||||
|
||||
/* Let's set up a new per-service "session" kernel keyring for each system service. This has the benefit that
|
||||
@ -2179,6 +2186,9 @@ static int setup_keyring(Unit *u, const ExecParameters *p, uid_t uid, gid_t gid)
|
||||
if (!(p->flags & EXEC_NEW_KEYRING))
|
||||
return 0;
|
||||
|
||||
if (context->keyring_mode == EXEC_KEYRING_INHERIT)
|
||||
return 0;
|
||||
|
||||
keyring = keyctl(KEYCTL_JOIN_SESSION_KEYRING, 0, 0, 0, 0);
|
||||
if (keyring == -1) {
|
||||
if (errno == ENOSYS)
|
||||
@ -2213,6 +2223,55 @@ static int setup_keyring(Unit *u, const ExecParameters *p, uid_t uid, gid_t gid)
|
||||
if (keyctl(KEYCTL_CHOWN, keyring, uid, gid, 0) < 0)
|
||||
return log_error_errno(errno, "Failed to change ownership of session keyring: %m");
|
||||
|
||||
/* When requested link the user keyring into the session keyring. */
|
||||
if (context->keyring_mode == EXEC_KEYRING_SHARED) {
|
||||
uid_t saved_uid;
|
||||
gid_t saved_gid;
|
||||
|
||||
/* Acquiring a reference to the user keyring is nasty. We briefly change identity in order to get things
|
||||
* set up properly by the kernel. If we don't do that then we can't create it atomically, and that
|
||||
* sucks for parallel execution. This mimics what pam_keyinit does, too.*/
|
||||
|
||||
saved_uid = getuid();
|
||||
saved_gid = getgid();
|
||||
|
||||
if (gid_is_valid(gid) && gid != saved_gid) {
|
||||
if (setregid(gid, -1) < 0)
|
||||
return log_error_errno(errno, "Failed to change GID for user keyring: %m");
|
||||
}
|
||||
|
||||
if (uid_is_valid(uid) && uid != saved_uid) {
|
||||
if (setreuid(uid, -1) < 0) {
|
||||
(void) setregid(saved_gid, -1);
|
||||
return log_error_errno(errno, "Failed to change UID for user keyring: %m");
|
||||
}
|
||||
}
|
||||
|
||||
if (keyctl(KEYCTL_LINK,
|
||||
KEY_SPEC_USER_KEYRING,
|
||||
KEY_SPEC_SESSION_KEYRING, 0, 0) < 0) {
|
||||
|
||||
r = -errno;
|
||||
|
||||
(void) setreuid(saved_uid, -1);
|
||||
(void) setregid(saved_gid, -1);
|
||||
|
||||
return log_error_errno(r, "Failed to link user keyring into session keyring: %m");
|
||||
}
|
||||
|
||||
if (uid_is_valid(uid) && uid != saved_uid) {
|
||||
if (setreuid(saved_uid, -1) < 0) {
|
||||
(void) setregid(saved_gid, -1);
|
||||
return log_error_errno(errno, "Failed to change UID back for user keyring: %m");
|
||||
}
|
||||
}
|
||||
|
||||
if (gid_is_valid(gid) && gid != saved_gid) {
|
||||
if (setregid(saved_gid, -1) < 0)
|
||||
return log_error_errno(errno, "Failed to change GID back for user keyring: %m");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2717,7 +2776,7 @@ static int exec_child(
|
||||
|
||||
(void) umask(context->umask);
|
||||
|
||||
r = setup_keyring(unit, params, uid, gid);
|
||||
r = setup_keyring(unit, context, params, uid, gid);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_KEYRING;
|
||||
*error_message = strdup("Failed to set up kernel keyring");
|
||||
@ -3595,7 +3654,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
|
||||
"%sMountAPIVFS: %s\n"
|
||||
"%sIgnoreSIGPIPE: %s\n"
|
||||
"%sMemoryDenyWriteExecute: %s\n"
|
||||
"%sRestrictRealtime: %s\n",
|
||||
"%sRestrictRealtime: %s\n"
|
||||
"%sKeyringMode: %s\n",
|
||||
prefix, c->umask,
|
||||
prefix, c->working_directory ? c->working_directory : "/",
|
||||
prefix, c->root_directory ? c->root_directory : "/",
|
||||
@ -3612,7 +3672,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
|
||||
prefix, yes_no(c->mount_apivfs),
|
||||
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_realtime),
|
||||
prefix, exec_keyring_mode_to_string(c->keyring_mode));
|
||||
|
||||
if (c->root_image)
|
||||
fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
|
||||
@ -4392,3 +4453,11 @@ static const char* const exec_directory_type_table[_EXEC_DIRECTORY_MAX] = {
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
|
||||
|
||||
static const char* const exec_keyring_mode_table[_EXEC_KEYRING_MODE_MAX] = {
|
||||
[EXEC_KEYRING_INHERIT] = "inherit",
|
||||
[EXEC_KEYRING_PRIVATE] = "private",
|
||||
[EXEC_KEYRING_SHARED] = "shared",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(exec_keyring_mode, ExecKeyringMode);
|
||||
|
@ -80,6 +80,14 @@ typedef enum ExecPreserveMode {
|
||||
_EXEC_PRESERVE_MODE_INVALID = -1
|
||||
} ExecPreserveMode;
|
||||
|
||||
typedef enum ExecKeyringMode {
|
||||
EXEC_KEYRING_INHERIT,
|
||||
EXEC_KEYRING_PRIVATE,
|
||||
EXEC_KEYRING_SHARED,
|
||||
_EXEC_KEYRING_MODE_MAX,
|
||||
_EXEC_KEYRING_MODE_INVALID = -1,
|
||||
} ExecKeyringMode;
|
||||
|
||||
struct ExecStatus {
|
||||
dual_timestamp start_timestamp;
|
||||
dual_timestamp exit_timestamp;
|
||||
@ -189,6 +197,8 @@ struct ExecContext {
|
||||
bool smack_process_label_ignore;
|
||||
char *smack_process_label;
|
||||
|
||||
ExecKeyringMode keyring_mode;
|
||||
|
||||
char **read_write_paths, **read_only_paths, **inaccessible_paths;
|
||||
unsigned long mount_flags;
|
||||
BindMount *bind_mounts;
|
||||
@ -368,5 +378,8 @@ ExecUtmpMode exec_utmp_mode_from_string(const char *s) _pure_;
|
||||
const char* exec_preserve_mode_to_string(ExecPreserveMode i) _const_;
|
||||
ExecPreserveMode exec_preserve_mode_from_string(const char *s) _pure_;
|
||||
|
||||
const char* exec_keyring_mode_to_string(ExecKeyringMode i) _const_;
|
||||
ExecKeyringMode exec_keyring_mode_from_string(const char *s) _pure_;
|
||||
|
||||
const char* exec_directory_type_to_string(ExecDirectoryType i) _const_;
|
||||
ExecDirectoryType exec_directory_type_from_string(const char *s) _pure_;
|
||||
|
@ -54,6 +54,7 @@ $1.CapabilityBoundingSet, config_parse_capability_set, 0,
|
||||
$1.AmbientCapabilities, config_parse_capability_set, 0, offsetof($1, exec_context.capability_ambient_set)
|
||||
$1.TimerSlackNSec, config_parse_nsec, 0, offsetof($1, exec_context.timer_slack_nsec)
|
||||
$1.NoNewPrivileges, config_parse_no_new_privileges, 0, offsetof($1, exec_context)
|
||||
$1.KeyringMode, config_parse_exec_keyring_mode, 0, offsetof($1, exec_context.keyring_mode)
|
||||
m4_ifdef(`HAVE_SECCOMP',
|
||||
`$1.SystemCallFilter, config_parse_syscall_filter, 0, offsetof($1, exec_context)
|
||||
$1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs)
|
||||
|
@ -4163,6 +4163,8 @@ int config_parse_protect_system(
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode, "Failed to parse keyring mode");
|
||||
|
||||
#define FOLLOW_MAX 8
|
||||
|
||||
static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
|
||||
|
@ -117,6 +117,7 @@ int config_parse_user_group(const char *unit, const char *filename, unsigned lin
|
||||
int config_parse_user_group_strv(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_restrict_namespaces(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_bind_paths(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_exec_keyring_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
|
||||
/* gperf prototypes */
|
||||
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
|
||||
|
@ -162,9 +162,13 @@ static void unit_init(Unit *u) {
|
||||
}
|
||||
|
||||
ec = unit_get_exec_context(u);
|
||||
if (ec)
|
||||
if (ec) {
|
||||
exec_context_init(ec);
|
||||
|
||||
ec->keyring_mode = MANAGER_IS_SYSTEM(u->manager) ?
|
||||
EXEC_KEYRING_PRIVATE : EXEC_KEYRING_INHERIT;
|
||||
}
|
||||
|
||||
kc = unit_get_kill_context(u);
|
||||
if (kc)
|
||||
kill_context_init(kc);
|
||||
|
@ -170,6 +170,7 @@ static int create_disk(
|
||||
"Type=oneshot\n"
|
||||
"RemainAfterExit=yes\n"
|
||||
"TimeoutSec=0\n" /* the binary handles timeouts anyway */
|
||||
"KeyringMode=shared\n" /* make sure we can share cached keys among instances */
|
||||
"ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
|
||||
"ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
|
||||
name, u, strempty(password), strempty(filtered),
|
||||
|
@ -99,6 +99,7 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, bool requir
|
||||
"Type=oneshot\n"
|
||||
"RemainAfterExit=yes\n"
|
||||
"TimeoutSec=0\n" /* the binary handles timeouts anyway */
|
||||
"KeyringMode=shared\n" /* make sure we can share cached keys among instances */
|
||||
"ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
|
||||
"ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
|
||||
d, d,
|
||||
|
@ -273,7 +273,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||
"Description", "Slice", "Type", "WorkingDirectory",
|
||||
"RootDirectory", "SyslogIdentifier", "ProtectSystem",
|
||||
"ProtectHome", "SELinuxContext", "Restart", "RootImage",
|
||||
"NotifyAccess", "RuntimeDirectoryPreserve", "Personality"))
|
||||
"NotifyAccess", "RuntimeDirectoryPreserve", "Personality",
|
||||
"KeyringMode"))
|
||||
r = sd_bus_message_append(m, "v", "s", eq);
|
||||
|
||||
else if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user