core: add {State,Cache,Log,Configuration}Directory= (#6384)
This introduces {State,Cache,Log,Configuration}Directory= those are
similar to RuntimeDirectory=. They create the directories under
/var/lib, /var/cache/, /var/log, or /etc, respectively, with the mode
specified in {State,Cache,Log,Configuration}DirectoryMode=.
This also fixes #6391.
This commit is contained in:
committed by
Lennart Poettering
parent
5230e31918
commit
3536f49e8f
+24
-3
@@ -1681,12 +1681,33 @@
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>StateDirectory=</varname></term>
|
||||
<term><varname>CacheDirectory=</varname></term>
|
||||
<term><varname>LogsDirectory=</varname></term>
|
||||
<term><varname>ConfigurationDirectory=</varname></term>
|
||||
|
||||
<listitem><para>Takes a whitespace-separated list of directory names. If set, as similar to
|
||||
<varname>RuntimeDirectory=</varname>, one or more directories including their parents by the specified names
|
||||
will be created below <filename>/var/lib</filename>, <filename>/var/cache</filename>, <filename>/var/log</filename>,
|
||||
or <filename>/etc</filename>, respectively, when the unit is started.
|
||||
Unlike <varname>RuntimeDirectory=</varname>, the directories are not removed when the unit is stopped.
|
||||
The lowest subdirectories will be owned by the user and group specified in <varname>User=</varname>
|
||||
and <varname>Group=</varname>. The options imply <varname>ReadWritePaths=</varname>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RuntimeDirectoryMode=</varname></term>
|
||||
<term><varname>StateDirectoryMode=</varname></term>
|
||||
<term><varname>CacheDirectoryMode=</varname></term>
|
||||
<term><varname>LogsDirectoryMode=</varname></term>
|
||||
<term><varname>ConfigurationDirectoryMode=</varname></term>
|
||||
|
||||
<listitem><para>Specifies the access mode of the directories specified in
|
||||
<varname>RuntimeDirectory=</varname> as an octal number. Defaults to
|
||||
<constant>0755</constant>. See "Permissions" in
|
||||
<varname>RuntimeDirectory=</varname>, <varname>StateDirectory=</varname>, <varname>CacheDirectory=</varname>,
|
||||
<varname>LogsDirectory=</varname>, or <varname>ConfigurationDirectory=</varname>, respectively, as an octal number.
|
||||
Defaults to <constant>0755</constant>. See "Permissions" in
|
||||
<citerefentry project='man-pages'><refentrytitle>path_resolution</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
for a discussion of the meaning of permission bits.
|
||||
</para></listitem>
|
||||
@@ -1727,7 +1748,7 @@
|
||||
services, so that they cannot be used to circumvent the restrictions of this option. Specifically, it is
|
||||
recommended to combine this option with <varname>SystemCallArchitectures=native</varname> or similar. If
|
||||
running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant> capability
|
||||
(e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname> is implied. </para></listitem>
|
||||
(e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname> is implied.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
||||
@@ -151,6 +151,18 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) {
|
||||
|
||||
case EXIT_KEYRING:
|
||||
return "KEYRING";
|
||||
|
||||
case EXIT_STATE_DIRECTORY:
|
||||
return "STATE_DIRECTORY";
|
||||
|
||||
case EXIT_CACHE_DIRECTORY:
|
||||
return "CACHE_DIRECTORY";
|
||||
|
||||
case EXIT_LOGS_DIRECTORY:
|
||||
return "LOGS_DIRECTORY";
|
||||
|
||||
case EXIT_CONFIGURATION_DIRECTORY:
|
||||
return "CONFIGURATION_DIRECTORY";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,10 @@ enum {
|
||||
EXIT_CHOWN,
|
||||
EXIT_SMACK_PROCESS_LABEL,
|
||||
EXIT_KEYRING,
|
||||
EXIT_STATE_DIRECTORY,
|
||||
EXIT_CACHE_DIRECTORY,
|
||||
EXIT_LOGS_DIRECTORY, /* 240 */
|
||||
EXIT_CONFIGURATION_DIRECTORY,
|
||||
};
|
||||
|
||||
typedef enum ExitStatusLevel {
|
||||
|
||||
+34
-10
@@ -851,9 +851,17 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||
SD_BUS_PROPERTY("SystemCallErrorNumber", "i", property_get_syscall_errno, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Personality", "s", property_get_personality, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RuntimeDirectoryPreserve", "s", property_get_exec_preserve_mode, offsetof(ExecContext, runtime_directory_preserve_mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME].mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME].paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("DataDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE].mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("DataDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE].paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("CacheDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE].mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("CacheDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE].paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("LogsDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS].mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("LogsDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS].paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ConfigurationDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ConfigurationDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RestrictNamespaces", "t", bus_property_get_ulong, offsetof(ExecContext, restrict_namespaces), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@@ -1701,7 +1709,7 @@ int bus_exec_context_set_transient_property(
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "RuntimeDirectoryMode")) {
|
||||
} else if (STR_IN_SET(name, "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode", "LogsDirectoryMode", "ConfigurationDirectoryMode")) {
|
||||
mode_t m;
|
||||
|
||||
r = sd_bus_message_read(message, "u", &m);
|
||||
@@ -1709,14 +1717,20 @@ int bus_exec_context_set_transient_property(
|
||||
return r;
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
c->runtime_directory_mode = m;
|
||||
ExecDirectoryType i;
|
||||
|
||||
unit_write_drop_in_private_format(u, mode, name, "RuntimeDirectoryMode=%040o", m);
|
||||
for (i = 0; i < _EXEC_DIRECTORY_MAX; i++)
|
||||
if (startswith(name, exec_directory_type_to_string(i))) {
|
||||
c->directories[i].mode = m;
|
||||
break;
|
||||
}
|
||||
|
||||
unit_write_drop_in_private_format(u, mode, name, "%s=%040o", name, m);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "RuntimeDirectory")) {
|
||||
} else if (STR_IN_SET(name, "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory")) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
char **p;
|
||||
|
||||
@@ -1726,22 +1740,32 @@ int bus_exec_context_set_transient_property(
|
||||
|
||||
STRV_FOREACH(p, l) {
|
||||
if (!filename_is_valid(*p))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Runtime directory is not valid %s", *p);
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s is not valid %s", name, *p);
|
||||
}
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
char ***dirs = NULL;
|
||||
ExecDirectoryType i;
|
||||
|
||||
for (i = 0; i < _EXEC_DIRECTORY_MAX; i++)
|
||||
if (streq(name, exec_directory_type_to_string(i))) {
|
||||
dirs = &c->directories[i].paths;
|
||||
break;
|
||||
}
|
||||
|
||||
assert(dirs);
|
||||
|
||||
if (strv_isempty(l)) {
|
||||
c->runtime_directory = strv_free(c->runtime_directory);
|
||||
*dirs = strv_free(*dirs);
|
||||
unit_write_drop_in_private_format(u, mode, name, "%s=", name);
|
||||
} else {
|
||||
r = strv_extend_strv(&c->runtime_directory, l, true);
|
||||
r = strv_extend_strv(dirs, l, true);
|
||||
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
joined = strv_join_quoted(c->runtime_directory);
|
||||
joined = strv_join_quoted(*dirs);
|
||||
if (!joined)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
+91
-34
@@ -1839,39 +1839,68 @@ static int setup_private_users(uid_t uid, gid_t gid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_runtime_directory(
|
||||
static int setup_exec_directory(
|
||||
const ExecContext *context,
|
||||
const ExecParameters *params,
|
||||
uid_t uid,
|
||||
gid_t gid) {
|
||||
gid_t gid,
|
||||
bool manager_is_system,
|
||||
ExecDirectoryType type,
|
||||
int *exit_status) {
|
||||
|
||||
static const int exit_status_table[_EXEC_DIRECTORY_MAX] = {
|
||||
[EXEC_DIRECTORY_RUNTIME] = EXIT_RUNTIME_DIRECTORY,
|
||||
[EXEC_DIRECTORY_STATE] = EXIT_STATE_DIRECTORY,
|
||||
[EXEC_DIRECTORY_CACHE] = EXIT_CACHE_DIRECTORY,
|
||||
[EXEC_DIRECTORY_LOGS] = EXIT_LOGS_DIRECTORY,
|
||||
[EXEC_DIRECTORY_CONFIGURATION] = EXIT_CONFIGURATION_DIRECTORY,
|
||||
};
|
||||
char **rt;
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
assert(params);
|
||||
assert(type >= 0 && type < _EXEC_DIRECTORY_MAX);
|
||||
assert(exit_status);
|
||||
|
||||
STRV_FOREACH(rt, context->runtime_directory) {
|
||||
if (!params->prefix[type])
|
||||
return 0;
|
||||
|
||||
if (manager_is_system) {
|
||||
if (!uid_is_valid(uid))
|
||||
uid = 0;
|
||||
if (!gid_is_valid(gid))
|
||||
gid = 0;
|
||||
}
|
||||
|
||||
STRV_FOREACH(rt, context->directories[type].paths) {
|
||||
_cleanup_free_ char *p;
|
||||
|
||||
p = strjoin(params->runtime_prefix, "/", *rt);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
p = strjoin(params->prefix[type], "/", *rt);
|
||||
if (!p) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = mkdir_parents_label(p, 0755);
|
||||
if (r < 0)
|
||||
return r;
|
||||
goto fail;
|
||||
|
||||
r = mkdir_p_label(p, context->runtime_directory_mode);
|
||||
r = mkdir_p_label(p, context->directories[type].mode);
|
||||
if (r < 0)
|
||||
return r;
|
||||
goto fail;
|
||||
|
||||
r = chmod_and_chown(p, context->runtime_directory_mode, uid, gid);
|
||||
r = chmod_and_chown(p, context->directories[type].mode, uid, gid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
*exit_status = exit_status_table[type];
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int setup_smack(
|
||||
@@ -1917,29 +1946,40 @@ static int compile_read_write_paths(
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
char **rt;
|
||||
ExecDirectoryType i;
|
||||
|
||||
/* Compile the list of writable paths. This is the combination of
|
||||
* the explicitly configured paths, plus all runtime directories. */
|
||||
|
||||
if (strv_isempty(context->read_write_paths) &&
|
||||
strv_isempty(context->runtime_directory)) {
|
||||
*ret = NULL; /* NOP if neither is set */
|
||||
return 0;
|
||||
if (strv_isempty(context->read_write_paths)) {
|
||||
for (i = 0; i < _EXEC_DIRECTORY_MAX; i++)
|
||||
if (!strv_isempty(context->directories[i].paths))
|
||||
break;
|
||||
|
||||
if (i == _EXEC_DIRECTORY_MAX) {
|
||||
*ret = NULL; /* NOP if neither is set */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
l = strv_copy(context->read_write_paths);
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
STRV_FOREACH(rt, context->runtime_directory) {
|
||||
char *s;
|
||||
for (i = 0; i < _EXEC_DIRECTORY_MAX; i++) {
|
||||
if (!params->prefix[i])
|
||||
continue;
|
||||
|
||||
s = strjoin(params->runtime_prefix, "/", *rt);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
STRV_FOREACH(rt, context->directories[i].paths) {
|
||||
char *s;
|
||||
|
||||
if (strv_consume(&l, s) < 0)
|
||||
return -ENOMEM;
|
||||
s = strjoin(params->prefix[i], "/", *rt);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
if (strv_consume(&l, s) < 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
*ret = l;
|
||||
@@ -2269,6 +2309,7 @@ static int exec_child(
|
||||
gid_t gid = GID_INVALID;
|
||||
int i, r, ngids = 0;
|
||||
unsigned n_fds;
|
||||
ExecDirectoryType dt;
|
||||
|
||||
assert(unit);
|
||||
assert(command);
|
||||
@@ -2556,12 +2597,10 @@ static int exec_child(
|
||||
}
|
||||
}
|
||||
|
||||
if (!strv_isempty(context->runtime_directory) && params->runtime_prefix) {
|
||||
r = setup_runtime_directory(context, params, uid, gid);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_RUNTIME_DIRECTORY;
|
||||
for (dt = 0; dt < _EXEC_DIRECTORY_MAX; dt++) {
|
||||
r = setup_exec_directory(context, params, uid, gid, MANAGER_IS_SYSTEM(unit->manager), dt, exit_status);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = build_environment(
|
||||
@@ -3049,6 +3088,8 @@ int exec_spawn(Unit *unit,
|
||||
}
|
||||
|
||||
void exec_context_init(ExecContext *c) {
|
||||
ExecDirectoryType i;
|
||||
|
||||
assert(c);
|
||||
|
||||
c->umask = 0022;
|
||||
@@ -3059,13 +3100,15 @@ void exec_context_init(ExecContext *c) {
|
||||
c->ignore_sigpipe = true;
|
||||
c->timer_slack_nsec = NSEC_INFINITY;
|
||||
c->personality = PERSONALITY_INVALID;
|
||||
c->runtime_directory_mode = 0755;
|
||||
for (i = 0; i < _EXEC_DIRECTORY_MAX; i++)
|
||||
c->directories[i].mode = 0755;
|
||||
c->capability_bounding_set = CAP_ALL;
|
||||
c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
|
||||
}
|
||||
|
||||
void exec_context_done(ExecContext *c) {
|
||||
unsigned l;
|
||||
ExecDirectoryType i;
|
||||
|
||||
assert(c);
|
||||
|
||||
@@ -3109,7 +3152,8 @@ void exec_context_done(ExecContext *c) {
|
||||
c->syscall_archs = set_free(c->syscall_archs);
|
||||
c->address_families = set_free(c->address_families);
|
||||
|
||||
c->runtime_directory = strv_free(c->runtime_directory);
|
||||
for (i = 0; i < _EXEC_DIRECTORY_MAX; i++)
|
||||
c->directories[i].paths = strv_free(c->directories[i].paths);
|
||||
}
|
||||
|
||||
int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_prefix) {
|
||||
@@ -3120,7 +3164,7 @@ int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_p
|
||||
if (!runtime_prefix)
|
||||
return 0;
|
||||
|
||||
STRV_FOREACH(i, c->runtime_directory) {
|
||||
STRV_FOREACH(i, c->directories[EXEC_DIRECTORY_RUNTIME].paths) {
|
||||
_cleanup_free_ char *p;
|
||||
|
||||
p = strjoin(runtime_prefix, "/", *i);
|
||||
@@ -3376,6 +3420,7 @@ static void strv_fprintf(FILE *f, char **l) {
|
||||
void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
|
||||
char **e, **d;
|
||||
unsigned i;
|
||||
ExecDirectoryType dt;
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
@@ -3431,12 +3476,14 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
|
||||
STRV_FOREACH(e, c->pass_environment)
|
||||
fprintf(f, "%sPassEnvironment: %s\n", prefix, *e);
|
||||
|
||||
fprintf(f, "%sRuntimeDirectoryMode: %04o\n", prefix, c->runtime_directory_mode);
|
||||
|
||||
fprintf(f, "%sRuntimeDirectoryPreserve: %s\n", prefix, exec_preserve_mode_to_string(c->runtime_directory_preserve_mode));
|
||||
|
||||
STRV_FOREACH(d, c->runtime_directory)
|
||||
fprintf(f, "%sRuntimeDirectory: %s\n", prefix, *d);
|
||||
for (dt = 0; dt < _EXEC_DIRECTORY_MAX; dt++) {
|
||||
fprintf(f, "%s%sMode: %04o\n", prefix, exec_directory_type_to_string(dt), c->directories[dt].mode);
|
||||
|
||||
STRV_FOREACH(d, c->directories[dt].paths)
|
||||
fprintf(f, "%s%s: %s\n", prefix, exec_directory_type_to_string(dt), *d);
|
||||
}
|
||||
|
||||
if (c->nice_set)
|
||||
fprintf(f,
|
||||
@@ -4185,3 +4232,13 @@ static const char* const exec_preserve_mode_table[_EXEC_PRESERVE_MODE_MAX] = {
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode, ExecPreserveMode, EXEC_PRESERVE_YES);
|
||||
|
||||
static const char* const exec_directory_type_table[_EXEC_DIRECTORY_MAX] = {
|
||||
[EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectory",
|
||||
[EXEC_DIRECTORY_STATE] = "StateDirectory",
|
||||
[EXEC_DIRECTORY_CACHE] = "CacheDirectory",
|
||||
[EXEC_DIRECTORY_LOGS] = "LogsDirectory",
|
||||
[EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectory",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
|
||||
|
||||
+20
-3
@@ -108,6 +108,21 @@ struct ExecRuntime {
|
||||
int netns_storage_socket[2];
|
||||
};
|
||||
|
||||
typedef enum ExecDirectoryType {
|
||||
EXEC_DIRECTORY_RUNTIME = 0,
|
||||
EXEC_DIRECTORY_STATE,
|
||||
EXEC_DIRECTORY_CACHE,
|
||||
EXEC_DIRECTORY_LOGS,
|
||||
EXEC_DIRECTORY_CONFIGURATION,
|
||||
_EXEC_DIRECTORY_MAX,
|
||||
_EXEC_DIRECTORY_INVALID = -1,
|
||||
} ExecDirectoryType;
|
||||
|
||||
typedef struct ExecDirectory {
|
||||
char **paths;
|
||||
mode_t mode;
|
||||
} ExecDirectory;
|
||||
|
||||
struct ExecContext {
|
||||
char **environment;
|
||||
char **environment_files;
|
||||
@@ -217,9 +232,8 @@ struct ExecContext {
|
||||
Set *address_families;
|
||||
bool address_families_whitelist:1;
|
||||
|
||||
char **runtime_directory;
|
||||
mode_t runtime_directory_mode;
|
||||
ExecPreserveMode runtime_directory_preserve_mode;
|
||||
ExecDirectory directories[_EXEC_DIRECTORY_MAX];
|
||||
|
||||
bool memory_deny_write_execute;
|
||||
bool restrict_realtime;
|
||||
@@ -265,7 +279,7 @@ struct ExecParameters {
|
||||
CGroupMask cgroup_supported;
|
||||
const char *cgroup_path;
|
||||
|
||||
const char *runtime_prefix;
|
||||
char **prefix;
|
||||
|
||||
const char *confirm_spawn;
|
||||
|
||||
@@ -342,3 +356,6 @@ 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_directory_type_to_string(ExecDirectoryType i) _const_;
|
||||
ExecDirectoryType exec_directory_type_from_string(const char *s) _pure_;
|
||||
|
||||
@@ -104,9 +104,17 @@ $1.ProtectHome, config_parse_protect_home, 0,
|
||||
$1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context)
|
||||
$1.MountAPIVFS, config_parse_bool, 0, offsetof($1, exec_context.mount_apivfs)
|
||||
$1.Personality, config_parse_personality, 0, offsetof($1, exec_context.personality)
|
||||
$1.RuntimeDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.runtime_directory_mode)
|
||||
$1.RuntimeDirectoryPreserve, config_parse_runtime_preserve_mode, 0, offsetof($1, exec_context.runtime_directory_preserve_mode)
|
||||
$1.RuntimeDirectory, config_parse_runtime_directory, 0, offsetof($1, exec_context.runtime_directory)
|
||||
$1.RuntimeDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_RUNTIME].mode)
|
||||
$1.RuntimeDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_RUNTIME].paths)
|
||||
$1.DataDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_STATE].mode)
|
||||
$1.DataDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_STATE].paths)
|
||||
$1.CacheDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_CACHE].mode)
|
||||
$1.CacheDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_CACHE].paths)
|
||||
$1.LogsDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_LOGS].mode)
|
||||
$1.LogsDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_LOGS].paths)
|
||||
$1.ConfigurationDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].mode)
|
||||
$1.ConfigurationDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].paths)
|
||||
m4_ifdef(`HAVE_PAM',
|
||||
`$1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name)',
|
||||
`$1.PAMName, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
|
||||
|
||||
@@ -3703,7 +3703,7 @@ int config_parse_job_mode_isolate(
|
||||
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
|
||||
|
||||
int config_parse_runtime_directory(
|
||||
int config_parse_exec_directories(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
@@ -3754,7 +3754,7 @@ int config_parse_runtime_directory(
|
||||
|
||||
if (!path_is_safe(k) || path_is_absolute(k)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Runtime directory is not valid, ignoring assignment: %s", rvalue);
|
||||
"%s is not valid, ignoring assignment: %s", lvalue, rvalue);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ int config_parse_exec_apparmor_profile(const char *unit, const char *filename, u
|
||||
int config_parse_exec_smack_process_label(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_address_families(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_runtime_preserve_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);
|
||||
int config_parse_runtime_directory(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_directories(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_set_status(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_namespace_path_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_no_new_privileges(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);
|
||||
|
||||
+57
-12
@@ -36,6 +36,7 @@
|
||||
|
||||
#include "sd-daemon.h"
|
||||
#include "sd-messages.h"
|
||||
#include "sd-path.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "audit-fd.h"
|
||||
@@ -52,6 +53,7 @@
|
||||
#include "dirent-util.h"
|
||||
#include "env-util.h"
|
||||
#include "escape.h"
|
||||
#include "execute.h"
|
||||
#include "exec-util.h"
|
||||
#include "exit-status.h"
|
||||
#include "fd-util.h"
|
||||
@@ -556,6 +558,48 @@ static int manager_default_environment(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int manager_setup_prefix(Manager *m) {
|
||||
struct table_entry {
|
||||
uint64_t type;
|
||||
const char *suffix;
|
||||
};
|
||||
|
||||
static const struct table_entry paths_system[_EXEC_DIRECTORY_MAX] = {
|
||||
[EXEC_DIRECTORY_RUNTIME] = { SD_PATH_SYSTEM_RUNTIME, NULL },
|
||||
[EXEC_DIRECTORY_STATE] = { SD_PATH_SYSTEM_STATE_PRIVATE, NULL },
|
||||
[EXEC_DIRECTORY_CACHE] = { SD_PATH_SYSTEM_STATE_CACHE, NULL },
|
||||
[EXEC_DIRECTORY_LOGS] = { SD_PATH_SYSTEM_STATE_LOGS, NULL },
|
||||
[EXEC_DIRECTORY_CONFIGURATION] = { SD_PATH_SYSTEM_CONFIGURATION, NULL },
|
||||
};
|
||||
|
||||
static const struct table_entry paths_user[_EXEC_DIRECTORY_MAX] = {
|
||||
[EXEC_DIRECTORY_RUNTIME] = { SD_PATH_USER_RUNTIME, NULL },
|
||||
[EXEC_DIRECTORY_STATE] = { SD_PATH_USER_CONFIGURATION, NULL },
|
||||
[EXEC_DIRECTORY_CACHE] = { SD_PATH_SYSTEM_STATE_CACHE, NULL },
|
||||
[EXEC_DIRECTORY_LOGS] = { SD_PATH_SYSTEM_CONFIGURATION, "log" },
|
||||
[EXEC_DIRECTORY_CONFIGURATION] = { SD_PATH_SYSTEM_CONFIGURATION, NULL },
|
||||
};
|
||||
|
||||
const struct table_entry *p;
|
||||
ExecDirectoryType i;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (MANAGER_IS_SYSTEM(m))
|
||||
p = paths_system;
|
||||
else
|
||||
p = paths_user;
|
||||
|
||||
for (i = 0; i < _EXEC_DIRECTORY_MAX; i++) {
|
||||
r = sd_path_home(p[i].type, p[i].suffix, &m->prefix[i]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
|
||||
Manager *m;
|
||||
int r;
|
||||
@@ -672,6 +716,10 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
|
||||
|
||||
m->taint_usr = dir_is_empty("/usr") > 0;
|
||||
|
||||
r = manager_setup_prefix(m);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
*_m = m;
|
||||
return 0;
|
||||
|
||||
@@ -692,7 +740,6 @@ static int manager_setup_notify(Manager *m) {
|
||||
.sa.sa_family = AF_UNIX,
|
||||
};
|
||||
static const int one = 1;
|
||||
const char *e;
|
||||
|
||||
/* First free all secondary fields */
|
||||
m->notify_socket = mfree(m->notify_socket);
|
||||
@@ -704,13 +751,7 @@ static int manager_setup_notify(Manager *m) {
|
||||
|
||||
fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE);
|
||||
|
||||
e = manager_get_runtime_prefix(m);
|
||||
if (!e) {
|
||||
log_error("Failed to determine runtime prefix.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
m->notify_socket = strappend(e, "/systemd/notify");
|
||||
m->notify_socket = strappend(m->prefix[EXEC_DIRECTORY_RUNTIME], "/systemd/notify");
|
||||
if (!m->notify_socket)
|
||||
return log_oom();
|
||||
|
||||
@@ -3309,12 +3350,16 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
|
||||
return hashmap_get(m->units_requiring_mounts_for, streq(p, "/") ? "" : p);
|
||||
}
|
||||
|
||||
const char *manager_get_runtime_prefix(Manager *m) {
|
||||
int manager_set_exec_params(Manager *m, ExecParameters *p) {
|
||||
assert(m);
|
||||
assert(p);
|
||||
|
||||
return MANAGER_IS_SYSTEM(m) ?
|
||||
"/run" :
|
||||
getenv("XDG_RUNTIME_DIR");
|
||||
p->environment = m->environment;
|
||||
p->confirm_spawn = manager_get_confirm_spawn(m);
|
||||
p->cgroup_supported = m->cgroup_supported;
|
||||
p->prefix = m->prefix;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_update_failed_units(Manager *m, Unit *u, bool failed) {
|
||||
|
||||
+4
-1
@@ -316,6 +316,9 @@ struct Manager {
|
||||
const char *invocation_log_format_string;
|
||||
|
||||
int first_boot; /* tri-state */
|
||||
|
||||
/* prefixes of e.g. RuntimeDirectory= */
|
||||
char *prefix[_EXEC_DIRECTORY_MAX];
|
||||
};
|
||||
|
||||
#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM)
|
||||
@@ -380,7 +383,7 @@ void manager_flip_auto_status(Manager *m, bool enable);
|
||||
|
||||
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path);
|
||||
|
||||
const char *manager_get_runtime_prefix(Manager *m);
|
||||
int manager_set_exec_params(Manager *m, ExecParameters *p);
|
||||
|
||||
ManagerState manager_state(Manager *m);
|
||||
|
||||
|
||||
+5
-5
@@ -770,12 +770,12 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
exec_params.environment = UNIT(m)->manager->environment;
|
||||
exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(m)->manager);
|
||||
exec_params.cgroup_supported = UNIT(m)->manager->cgroup_supported;
|
||||
r = manager_set_exec_params(UNIT(m)->manager, &exec_params);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
exec_params.cgroup_path = UNIT(m)->cgroup_path;
|
||||
exec_params.cgroup_delegate = m->cgroup_context.delegate;
|
||||
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(m)->manager);
|
||||
|
||||
r = exec_spawn(UNIT(m),
|
||||
c,
|
||||
@@ -808,7 +808,7 @@ static void mount_enter_dead(Mount *m, MountResult f) {
|
||||
exec_runtime_destroy(m->exec_runtime);
|
||||
m->exec_runtime = exec_runtime_unref(m->exec_runtime);
|
||||
|
||||
exec_context_destroy_runtime_directory(&m->exec_context, manager_get_runtime_prefix(UNIT(m)->manager));
|
||||
exec_context_destroy_runtime_directory(&m->exec_context, UNIT(m)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
|
||||
|
||||
unit_unref_uid_gid(UNIT(m), true);
|
||||
|
||||
|
||||
+6
-5
@@ -1342,7 +1342,11 @@ static int service_spawn(
|
||||
}
|
||||
}
|
||||
|
||||
final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
|
||||
r = manager_set_exec_params(UNIT(s)->manager, &exec_params);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
final_env = strv_env_merge(2, exec_params.environment, our_env, NULL);
|
||||
if (!final_env)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -1359,11 +1363,8 @@ static int service_spawn(
|
||||
exec_params.fd_names = fd_names;
|
||||
exec_params.n_storage_fds = n_storage_fds;
|
||||
exec_params.n_socket_fds = n_socket_fds;
|
||||
exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(s)->manager);
|
||||
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
|
||||
exec_params.cgroup_path = path;
|
||||
exec_params.cgroup_delegate = s->cgroup_context.delegate;
|
||||
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
|
||||
exec_params.watchdog_usec = s->watchdog_usec;
|
||||
exec_params.selinux_context_net = s->socket_fd_selinux_context_net;
|
||||
if (s->type == SERVICE_IDLE)
|
||||
@@ -1525,7 +1526,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
||||
if (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_NO ||
|
||||
(s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_RESTART && !service_will_restart(s)))
|
||||
/* Also, remove the runtime directory */
|
||||
exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
|
||||
exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
|
||||
|
||||
/* Get rid of the IPC bits of the user */
|
||||
unit_unref_uid_gid(UNIT(s), true);
|
||||
|
||||
+6
-5
@@ -1790,13 +1790,13 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_set_exec_params(UNIT(s)->manager, &exec_params);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
exec_params.argv = c->argv;
|
||||
exec_params.environment = UNIT(s)->manager->environment;
|
||||
exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(s)->manager);
|
||||
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
|
||||
exec_params.cgroup_path = UNIT(s)->cgroup_path;
|
||||
exec_params.cgroup_delegate = s->cgroup_context.delegate;
|
||||
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
|
||||
|
||||
r = exec_spawn(UNIT(s),
|
||||
c,
|
||||
@@ -1814,6 +1814,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
|
||||
return r;
|
||||
|
||||
*_pid = pid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1912,7 +1913,7 @@ static void socket_enter_dead(Socket *s, SocketResult f) {
|
||||
exec_runtime_destroy(s->exec_runtime);
|
||||
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
|
||||
|
||||
exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
|
||||
exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
|
||||
|
||||
unit_unref_uid_gid(UNIT(s), true);
|
||||
|
||||
|
||||
+7
-6
@@ -630,18 +630,18 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
|
||||
|
||||
r = unit_setup_dynamic_creds(UNIT(s));
|
||||
if (r < 0)
|
||||
return r;
|
||||
goto fail;
|
||||
|
||||
r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
exec_params.environment = UNIT(s)->manager->environment;
|
||||
exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(s)->manager);
|
||||
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
|
||||
r = manager_set_exec_params(UNIT(s)->manager, &exec_params);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
exec_params.cgroup_path = UNIT(s)->cgroup_path;
|
||||
exec_params.cgroup_delegate = s->cgroup_context.delegate;
|
||||
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
|
||||
|
||||
r = exec_spawn(UNIT(s),
|
||||
c,
|
||||
@@ -664,6 +664,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
|
||||
|
||||
fail:
|
||||
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -678,7 +679,7 @@ static void swap_enter_dead(Swap *s, SwapResult f) {
|
||||
exec_runtime_destroy(s->exec_runtime);
|
||||
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
|
||||
|
||||
exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
|
||||
exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
|
||||
|
||||
unit_unref_uid_gid(UNIT(s), true);
|
||||
|
||||
|
||||
@@ -145,15 +145,11 @@ static int specifier_cgroup_slice(char specifier, void *data, void *userdata, ch
|
||||
|
||||
static int specifier_runtime(char specifier, void *data, void *userdata, char **ret) {
|
||||
Unit *u = userdata;
|
||||
const char *e;
|
||||
char *n = NULL;
|
||||
|
||||
assert(u);
|
||||
|
||||
e = manager_get_runtime_prefix(u->manager);
|
||||
if (!e)
|
||||
return -EOPNOTSUPP;
|
||||
n = strdup(e);
|
||||
n = strdup(u->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
@@ -548,7 +548,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
|
||||
} else if (streq(field, "RuntimeDirectoryMode")) {
|
||||
} else if (STR_IN_SET(field, "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode", "LogsDirectoryMode", "ConfigurationDirectoryMode")) {
|
||||
mode_t mode;
|
||||
|
||||
r = parse_mode(eq, &mode);
|
||||
@@ -557,7 +557,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||
|
||||
r = sd_bus_message_append(m, "v", "u", mode);
|
||||
|
||||
} else if (streq(field, "RuntimeDirectory")) {
|
||||
} else if (STR_IN_SET(field, "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory")) {
|
||||
const char *p;
|
||||
|
||||
r = sd_bus_message_open_container(m, 'v', "as");
|
||||
|
||||
Reference in New Issue
Block a user