core/exec-invoke: chdir("/") after chroot in apply_root_directory
apply_root_directory() calls chroot() but never pairs it with a
chdir("/"). Moving cwd into the new root is left to the subsequent
apply_working_directory() call. That delegation breaks when the unit
sets WorkingDirectory=-/path (working_directory_missing_ok):
apply_root_directory() apply_working_directory()
chroot(new_root) --> chdir(wd) fails (ENOENT)
return 0 return 0 /* missing_ok */
chroot(2) changes only the process root, not cwd. With cwd still
resolving to the pre-chroot host dentry, the process runs with the
kernel root pointing at the new root while relative-path accesses
and /proc/self/cwd reach paths outside RootDirectory=.
Only the chroot-only branch (exec_needs_mount_namespace() == false)
is affected. The mount-namespace branch uses pivot_root(), which
restructures the mount tree and makes the pre-chroot dentry
unreachable.
Fix by issuing chdir("/") immediately after the successful chroot()
in apply_root_directory() and propagating any failure with
EXIT_CHROOT, matching the standard chroot+chdir idiom and making
the chroot self-contained regardless of how
apply_working_directory() later handles a missing directory.
Assisted-by: kres (claude-opus-4-7)
Signed-off-by: Chris Mason <clm@meta.com>
This commit is contained in:
committed by
Lennart Poettering
parent
700d8e73d4
commit
4e02162a6e
+11
-1
@@ -4133,12 +4133,22 @@ static int apply_root_directory(
|
||||
assert(exit_status);
|
||||
|
||||
if (params->flags & EXEC_APPLY_CHROOT)
|
||||
if (!needs_mount_ns && context->root_directory)
|
||||
if (!needs_mount_ns && context->root_directory) {
|
||||
if (chroot(runtime->ephemeral_copy ?: context->root_directory) < 0) {
|
||||
*exit_status = EXIT_CHROOT;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* chroot(2) changes only the process root, not cwd. Move cwd into the new root
|
||||
* immediately so that a subsequent apply_working_directory() failure that is
|
||||
* silently ignored via working_directory_missing_ok cannot leave cwd pointing
|
||||
* at a pre-chroot dentry outside the new root. */
|
||||
if (chdir("/") < 0) {
|
||||
*exit_status = EXIT_CHROOT;
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user