fix(squash-lib): mirror host merged-usr symlinks in the squash loader - #2603
fix(squash-lib): mirror host merged-usr symlinks in the squash loader#2603prabhakarpujeri wants to merge 1 commit into
Conversation
Why not use the exact same code/steps in Can we use I do not mind duplicating some code if we need to. |
|
CC @challvy |
|
Thanks for the review! I tried both suggestions; unfortunately they don't work in this stage of the build:
What this change does instead is the same intent expressed stage-locally: replicate the host's exact symlink (copy the Happy to converge on a different shape if you prefer — as you said, duplicating a few lines here seemed acceptable, and the prefix/indirection layers of |
5450038 to
7548337
Compare
|
Thanks @prabhakarpujeri . LGTM. Plan to approve the PR once GitHub is up for the task. |
7548337 to
d76ac9f
Compare
The squash loader assembles its own root directory and creates
usr/bin, usr/sbin and usr/lib as plain directories, only symlinking
the top-level bin/sbin/lib to their usr counterparts.
On merged-usr hosts where /usr/sbin itself is a symlink (/usr/sbin ->
bin, e.g. Fedora 42+), binaries resolved on the host's unified tree
are installed into only one of the two split trees in the loader. In
particular the busybox module places its sh applet symlink at
usr/sbin/sh while /bin/sh == /usr/bin/sh stays missing, so the kernel
cannot execute the shebang of init-squash.sh:
Run /init as init process
Failed to execute /init (error -2)
This breaks the kdump squashfs image on Fedora 42+ (issue dracut-ng#2454).
Mirror the host layout instead: if the host directory is a symlink,
replicate the same symlink in the loader directory; otherwise create
a real directory as before. This is the root-cause fix for the
directory-layout problem identified in PR dracut-ng#2455, which proposed to
special-case only the busybox sh symlink.
Reproduced the failure on Fedora 44 (busybox, squashfs, qemu):
before the change the loader contains usr/sbin as a real directory
holding 'sh -> ../bin/busybox' with /usr/bin/sh absent, and booting
the image fails to execute /init with error -2. After the change the
loader has 'usr/sbin -> bin' and 'usr/bin/sh -> busybox', /init
executes, the squash image is mounted and the inner systemd initramfs
reaches initrd-switch-root.target.
Fixes: dracut-ng#2454
|
The difference between While looking at the code I found an issue in |
| # (/usr/bin/sh). The target text is copied from the host so | ||
| # that the link is valid both at boot time and while the | ||
| # loader directory is still being populated. | ||
| ln -sfn "$(readlink "${dracutsysrootdir-}/$_dir")" "$squashdir/$_dir" |
There was a problem hiding this comment.
What happens if the symlinks points to a directory that this loop does not create?
There was a problem hiding this comment.
Good question. The loop covers exactly the four paths merged-usr symlinks can point into — usr/bin, usr/sbin, usr/lib, squash — so a host symlink's target is always one the loop creates. E.g. on Fedora the host has /usr/sbin -> bin; the loop sees usr/sbin is a link, recreates it as usr/sbin -> bin in the loader, and usr/bin (created by the same loop, either as a real dir or as a symlink as the host demands) is the target bin resolves to. State after the loop on this host: usr/bin dir, usr/sbin -> bin, and busybox + sh reachable from both — which is also verified by the empirical before/after tests in the description (init boots into the inner systemd initramfs with the fix; Failed to execute /init (error -2) without).
Exotic host symlinks pointing outside the loop's set (e.g. /usr/sbin -> ../opt/sbin) would become a dangling symlink in the loader — same as today's behavior, and not harmful (nothing installs through that path, so the link is inert).
|
Agreed, that's a good follow-up direction. With #2619 (thanks for fixing that) the remaining obstacle for reusing Untangling |
Problem
The squash loader (squash-lib) assembles its own root directory and creates
usr/bin,usr/sbinandusr/libas plain directories, only symlinking the top-levelbin/sbin/libto their usr counterparts:On merged-usr hosts where
/usr/sbinitself is a symlink (/usr/sbin -> bin, e.g. Fedora 42+), binaries resolved on the host's unified tree are installed into only one of the two split trees in the loader. In particular the busybox module creates its applet links with a shell-sideln_r /usr/bin/busybox "$_path"(no symlink resolution by dracut-install in that path), soshphysically lands in the loader's realusr/sbin/directory while/bin/sh==/usr/bin/shstays missing. The kernel then cannot execute the shebang ofinit-squash.sh:This is what breaks the kdump squashfs image on Fedora 42+ in #2454. The main initramfs path does not hit this because
create_directories()in dracut.sh mirrors the host layout (if [ -L "/$d" ]→ install as symlink).Fix
Mirror the host layout in
squash_install(): if the host directory is a symlink, replicate the same symlink in the loader directory; otherwise create a real directory as before. Binaries installed to either merged tree (usr/sbin/fooorusr/bin/foo) then always land in the single shared tree, matching host semantics.Root-cause alternative to #2455: instead of special-casing the busybox
shsymlink, this fixes the directory structure itself, so it covers every binary — not justsh— for both the busybox and the non-busybox loader paths.Testing
Reproduced the exact failure from #2454 and verified the fix on two Fedora 44 systems (qemu/KVM guest boot on real hardware, busybox package installed, squashfs handler available,
PATHwith/usr/sbinfirst as in the kdump build environment):usr/sbinreal dir,sh -> ../bin/busyboxstranded there,usr/bin/shabsentusr/sbin -> bin,usr/bin/sh -> busyboxchrootinto extracted loader tree — the kernel's ENOENT path)failed to run command '/init': No such file or directory(error -2)/bin/shexecutes (exit 0)Run /init as init process→Failed to execute /init (error -2)/initexecutes,squashfsmounts,switch_rootinto the inner systemd initramfs, boot proceeds toinitrd-switch-root.target(ends there only because the synthetic test image has no realroot=device)Boot logs were captured from the VM serial console for both runs.
shellcheck modules.d/88squash-lib/module-setup.shclean.Fixes: #2454