What Happens
tool_unshadow (host-setup/linux/install-tools.sh) guards against removing a distro-owned file by
checking dpkg-query -S "$resolved". On a merged-usr host, where /bin and /sbin are symlinks to
their /usr/... counterparts, a shadow candidate spelled through the symlinked path (/bin/jq
rather than /usr/bin/jq) does not match any entry in dpkg's database, since dpkg records the
canonical /usr/bin/jq path. dpkg-query -S /bin/ls answers "no path found" on such a host even
though /bin/ls and /usr/bin/ls are the same file and /usr/bin/ls is dpkg-owned.
The Property That Triggers It
A PATH that puts /bin or /sbin ahead of $BIN_DIR on a merged-usr distro (Debian/Ubuntu's
default layout), where the shadowing copy is actually the distro package's own file, reached only
through the symlinked path name. This needs an unusual PATH order and is a pre-existing defect: the
literal-string PATH-order fix in #1644 does not change which path string dpkg-query -S is asked
about.
Impact
The ownership guard's if dpkg-query -S "$resolved" >/dev/null 2>&1; then warn ...; break; fi falls
through instead of warning, so tool_unshadow proceeds to run_root rm -f "$resolved" in
--upgrade mode, deleting a file dpkg still believes it owns. apt/dpkg state now disagrees with
the filesystem for that package until it is reinstalled or repaired.
Repro (constructed, illustrative)
# On a merged-usr host, /bin is a symlink to usr/bin.
dpkg-query -S /bin/ls # -> "dpkg-query: no path found matching pattern /bin/ls"
dpkg-query -S /usr/bin/ls # -> matches the owning package
Suggested Fix
Resolve $resolved to its canonical path (realpath or equivalent) before the dpkg-query -S
lookup, so a merged-usr symlink path and its canonical target both answer the same ownership
question.
Found during the local-strict-review pass on #1864 (the PR fixing #1644), scoped out of that PR
since it is a narrower, pre-existing edge case in a different function than the one #1644 fixed.
What Happens
tool_unshadow(host-setup/linux/install-tools.sh) guards against removing a distro-owned file bychecking
dpkg-query -S "$resolved". On a merged-usr host, where/binand/sbinare symlinks totheir
/usr/...counterparts, a shadow candidate spelled through the symlinked path (/bin/jqrather than
/usr/bin/jq) does not match any entry in dpkg's database, since dpkg records thecanonical
/usr/bin/jqpath.dpkg-query -S /bin/lsanswers "no path found" on such a host eventhough
/bin/lsand/usr/bin/lsare the same file and/usr/bin/lsis dpkg-owned.The Property That Triggers It
A
PATHthat puts/binor/sbinahead of$BIN_DIRon a merged-usr distro (Debian/Ubuntu'sdefault layout), where the shadowing copy is actually the distro package's own file, reached only
through the symlinked path name. This needs an unusual PATH order and is a pre-existing defect: the
literal-string PATH-order fix in #1644 does not change which path string
dpkg-query -Sis askedabout.
Impact
The ownership guard's
if dpkg-query -S "$resolved" >/dev/null 2>&1; then warn ...; break; fifallsthrough instead of warning, so
tool_unshadowproceeds torun_root rm -f "$resolved"in--upgrademode, deleting a file dpkg still believes it owns.apt/dpkgstate now disagrees withthe filesystem for that package until it is reinstalled or repaired.
Repro (constructed, illustrative)
Suggested Fix
Resolve
$resolvedto its canonical path (realpathor equivalent) before thedpkg-query -Slookup, so a merged-usr symlink path and its canonical target both answer the same ownership
question.
Found during the local-strict-review pass on #1864 (the PR fixing #1644), scoped out of that PR
since it is a narrower, pre-existing edge case in a different function than the one #1644 fixed.