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:
+54
-2
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user