core: make DynamicUser=1 and StateDirectory= work with TemporaryFileSystem=/var/lib

The /var/lib/private/foo -> /var/lib/foo symlink for StateDirectory and
DynamicUser is set up on the host filesystem, before the mount namespacing
is brought up. If an empty /var/lib is used, to ensure the service does not
see other services data, the symlink is then not available despite
/var/lib/private being set up as expected.

Make a list of symlinks that need to be set up, and create them after all
the namespaced filesystems have been created, but before any eventual
read-only switch is flipped.
This commit is contained in:
Luca Boccassi
2021-10-27 22:45:26 +01:00
parent d5bb2b0375
commit df61e79a5d
6 changed files with 95 additions and 3 deletions
+54 -2
View File
@@ -2384,7 +2384,9 @@ static int setup_exec_directory(
goto fail;
}
/* And link it up from the original place */
/* And link it up from the original place. Note that if a mount namespace is going to be
* used, then this symlink remains on the host, and a new one for the child namespace will
* be created later. */
r = symlink_idempotent(pp, p, true);
if (r < 0)
goto fail;
@@ -3148,6 +3150,49 @@ finish:
return r;
}
/* ret_symlinks will contain a list of pairs src:dest that describes
* the symlinks to create later on. For example, the symlinks needed
* to safely give private directories to DynamicUser=1 users. */
static int compile_symlinks(
const ExecContext *context,
const ExecParameters *params,
char ***ret_symlinks) {
_cleanup_strv_free_ char **symlinks = NULL;
int r;
assert(context);
assert(params);
assert(ret_symlinks);
for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
char **src;
if (!exec_directory_is_private(context, dt))
continue;
STRV_FOREACH(src, context->directories[dt].paths) {
_cleanup_free_ char *private_path = NULL, *path = NULL;
private_path = path_join(params->prefix[dt], "private", *src);
if (!private_path)
return -ENOMEM;
path = path_join(params->prefix[dt], *src);
if (!path)
return -ENOMEM;
r = strv_consume_pair(&symlinks, TAKE_PTR(private_path), TAKE_PTR(path));
if (r < 0)
return r;
}
}
*ret_symlinks = TAKE_PTR(symlinks);
return 0;
}
static bool insist_on_sandboxing(
const ExecContext *context,
const char *root_dir,
@@ -3194,7 +3239,7 @@ static int apply_mount_namespace(
const ExecRuntime *runtime,
char **error_path) {
_cleanup_strv_free_ char **empty_directories = NULL;
_cleanup_strv_free_ char **empty_directories = NULL, **symlinks = NULL;
const char *tmp_dir = NULL, *var_tmp_dir = NULL;
const char *root_dir = NULL, *root_image = NULL;
_cleanup_free_ char *creds_path = NULL, *incoming_dir = NULL, *propagate_dir = NULL;
@@ -3217,6 +3262,12 @@ static int apply_mount_namespace(
if (r < 0)
return r;
/* Symlinks for exec dirs are set up after other mounts, before they are
* made read-only. */
r = compile_symlinks(context, params, &symlinks);
if (r < 0)
return r;
needs_sandboxing = (params->flags & EXEC_APPLY_SANDBOXING) && !(command_flags & EXEC_COMMAND_FULLY_PRIVILEGED);
if (needs_sandboxing) {
/* The runtime struct only contains the parent of the private /tmp,
@@ -3300,6 +3351,7 @@ static int apply_mount_namespace(
needs_sandboxing ? context->exec_paths : NULL,
needs_sandboxing ? context->no_exec_paths : NULL,
empty_directories,
symlinks,
bind_mounts,
n_bind_mounts,
context->temporary_filesystems,