summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2019-06-25 10:06:03 +0200
committerGitHub <noreply@github.com>2019-06-25 10:06:03 +0200
commitc7e42ceb7a99538535ac9f3673b078768a51becf (patch)
tree9cad7beb045bcbd0e1a5899a956bb5883be09ee2
parentfab347489fcfafbc8367c86afc637ce1b81ae59e (diff)
parent5c6d40d13238e56699074fc1b01f4ac929ba62b8 (diff)
downloadsystemd-c7e42ceb7a99538535ac9f3673b078768a51becf.tar.gz
Merge pull request #12869 from poettering/dynamic-user-re-migrate
DynamicUser=1 state directory back migration
-rw-r--r--src/core/execute.c73
1 files changed, 54 insertions, 19 deletions
diff --git a/src/core/execute.c b/src/core/execute.c
index 426e57b8e0..acce8326fe 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -2099,27 +2099,30 @@ static int setup_exec_directory(
(type == EXEC_DIRECTORY_RUNTIME && context->runtime_directory_preserve_mode != EXEC_PRESERVE_NO))) {
_cleanup_free_ char *private_root = NULL;
- /* So, here's one extra complication when dealing with DynamicUser=1 units. In that case we
- * want to avoid leaving a directory around fully accessible that is owned by a dynamic user
- * whose UID is later on reused. To lock this down we use the same trick used by container
- * managers to prohibit host users to get access to files of the same UID in containers: we
- * place everything inside a directory that has an access mode of 0700 and is owned root:root,
- * so that it acts as security boundary for unprivileged host code. We then use fs namespacing
- * to make this directory permeable for the service itself.
+ /* So, here's one extra complication when dealing with DynamicUser=1 units. In that
+ * case we want to avoid leaving a directory around fully accessible that is owned by
+ * a dynamic user whose UID is later on reused. To lock this down we use the same
+ * trick used by container managers to prohibit host users to get access to files of
+ * the same UID in containers: we place everything inside a directory that has an
+ * access mode of 0700 and is owned root:root, so that it acts as security boundary
+ * for unprivileged host code. We then use fs namespacing to make this directory
+ * permeable for the service itself.
*
- * Specifically: for a service which wants a special directory "foo/" we first create a
- * directory "private/" with access mode 0700 owned by root:root. Then we place "foo" inside of
- * that directory (i.e. "private/foo/"), and make "foo" a symlink to "private/foo". This way,
- * privileged host users can access "foo/" as usual, but unprivileged host users can't look
- * into it. Inside of the namespaceof the container "private/" is replaced by a more liberally
- * accessible tmpfs, into which the host's "private/foo/" is mounted under the same name, thus
- * disabling the access boundary for the service and making sure it only gets access to the
- * dirs it needs but no others. Tricky? Yes, absolutely, but it works!
+ * Specifically: for a service which wants a special directory "foo/" we first create
+ * a directory "private/" with access mode 0700 owned by root:root. Then we place
+ * "foo" inside of that directory (i.e. "private/foo/"), and make "foo" a symlink to
+ * "private/foo". This way, privileged host users can access "foo/" as usual, but
+ * unprivileged host users can't look into it. Inside of the namespace of the unit
+ * "private/" is replaced by a more liberally accessible tmpfs, into which the host's
+ * "private/foo/" is mounted under the same name, thus disabling the access boundary
+ * for the service and making sure it only gets access to the dirs it needs but no
+ * others. Tricky? Yes, absolutely, but it works!
*
- * Note that we don't do this for EXEC_DIRECTORY_CONFIGURATION as that's assumed not to be
- * owned by the service itself.
- * Also, note that we don't do this for EXEC_DIRECTORY_RUNTIME as that's often used for sharing
- * files or sockets with other services. */
+ * Note that we don't do this for EXEC_DIRECTORY_CONFIGURATION as that's assumed not
+ * to be owned by the service itself.
+ *
+ * Also, note that we don't do this for EXEC_DIRECTORY_RUNTIME as that's often used
+ * for sharing files or sockets with other services. */
private_root = path_join(params->prefix[type], "private");
if (!private_root) {
@@ -2168,6 +2171,38 @@ static int setup_exec_directory(
goto fail;
} else {
+ _cleanup_free_ char *target = NULL;
+
+ if (type != EXEC_DIRECTORY_CONFIGURATION &&
+ readlink_and_make_absolute(p, &target) >= 0) {
+ _cleanup_free_ char *q = NULL;
+
+ /* This already exists and is a symlink? Interesting. Maybe it's one created
+ * by DynamicUser=1 (see above)? */
+
+ q = path_join(params->prefix[type], "private", *rt);
+ if (!q) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ if (path_equal(q, target)) {
+
+ /* Hmm, apparently DynamicUser= was once turned on for this service,
+ * but is no longer. Let's move the directory back up. */
+
+ if (unlink(p) < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ if (rename(q, p) < 0) {
+ r = -errno;
+ goto fail;
+ }
+ }
+ }
+
r = mkdir_label(p, context->directories[type].mode);
if (r < 0) {
if (r != -EEXIST)