diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index db491b49a0..73d18b1db2 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -1654,29 +1654,31 @@
RuntimeDirectory=
- Takes a list of directory names. If set, one
- or more directories by the specified names will be created
- below /run (for system services) or below
- $XDG_RUNTIME_DIR (for user services) when
- the unit is started, and removed when the unit is stopped.
- It is possible to preserve the directories if
- RuntimeDirectoryPreserve= is configured to
- or . The
- directories will have the access mode specified in
- RuntimeDirectoryMode=, and will be owned by
- the user and group specified in User= and
- Group=. Use this to manage one or more
- runtime directories of the unit and bind their lifetime to the
- daemon runtime. The specified directory names must be
- relative, and may not include a /, i.e.
- must refer to simple directories to create or remove. This is
- particularly useful for unprivileged daemons that cannot
- create runtime directories in /run due to
- lack of privileges, and to make sure the runtime directory is
- cleaned up automatically after use. For runtime directories
- that require more complex or different configuration or
- lifetime guarantees, please consider using
- tmpfiles.d5.
+ Takes a whitespace-separated list of directory names. The specified directory names must be
+ relative, and may not include . or ... If set, one or more directories
+ including their parents by the specified names will be created below /run (for system
+ services) or below $XDG_RUNTIME_DIR (for user services) when the unit is started. The
+ lowest subdirectories are removed when the unit is stopped. It is possible to preserve the directories if
+ RuntimeDirectoryPreserve= is configured to or .
+ The lowest subdirectories will have the access mode specified in RuntimeDirectoryMode=,
+ and be owned by the user and group specified in User= and Group=.
+ This implies ReadWritePaths=, that is, the directories specified
+ in this option are accessible with the access mode specified in RuntimeDirectoryMode=
+ even if ProtectSystem= is set to .
+ Use this to manage one or more runtime directories of the unit and bind their
+ lifetime to the daemon runtime. This is particularly useful for unprivileged daemons that cannot create
+ runtime directories in /run due to lack of privileges, and to make sure the runtime
+ directory is cleaned up automatically after use. For runtime directories that require more complex or
+ different configuration or lifetime guarantees, please consider using
+ tmpfiles.d5.
+
+ Example: if a system service unit has the following,
+ RuntimeDirectory=foo/bar baz
+ the service manager creates /run/foo (if it does not exist), /run/foo/bar,
+ and /run/baz. The directories /run/foo/bar and /run/baz
+ except /run/foo are owned by the user and group specified in User= and
+ Group=, and removed when the service is stopped.
+
@@ -1685,7 +1687,8 @@
Specifies the access mode of the directories specified in
RuntimeDirectory= as an octal number. Defaults to
0755. See "Permissions" in
- path_resolution7 for a discussion of the meaning of permission bits.
+ path_resolution7
+ for a discussion of the meaning of permission bits.
diff --git a/src/core/execute.c b/src/core/execute.c
index d1d660ffed..fd769b2973 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1858,6 +1858,10 @@ static int setup_runtime_directory(
if (!p)
return -ENOMEM;
+ r = mkdir_parents_label(p, 0755);
+ if (r < 0)
+ return r;
+
r = mkdir_p_label(p, context->runtime_directory_mode);
if (r < 0)
return r;
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 15d392cdde..00b7f69cd8 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3752,7 +3752,7 @@ int config_parse_runtime_directory(
continue;
}
- if (!filename_is_valid(k)) {
+ 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);
continue;