Bug#638068: Root cause: busybox binary in initrd.img is incorrectly overwritten by klibc hook
Hi,
I've identified the root cause of this issue: busybox hook is called
_before_ klibc one. This ends up with /bin/sh binary in the generated
initrd.img being a copy of (or a symlink to) system
/usr/lib/klibc/bin/sh binary whereas it is expected to be a copy of
(or a symlink to) system /bin/busybox binary.
The explanations in details.
Up to initramfs-tools 0.98.8, an error message should have warn us.
When running e.g. dpkg -i initramfs-tools_0.98.8_all.deb, the
following error is displayed on console:
ln: failed to create symbolic link
`/tmp/mkinitramfs_o2WpcY/bin/sh': File exist
Following commit 8f8299d9ba017d2a5af853a52be37ee50c89fac2
(mkinitramfs: copy over on
build instead of using symlink tree) from maximilian attems, this
error has disappeared in initramfs-tools 0.99. More on this later.
So, why are we getting this ln error with initramfs-tools 0.98.8?
Tracing an initramfs-tools run reveals that busybox hook is called
first, most notably executing:
rm -f ${DESTDIR}/bin/sh
rm -f ${DESTDIR}/bin/busybox
copy_exec ${BUSYBOXDIR}/busybox /bin/busybox
ln -s ${BUSYBOXDIR}/busybox ${DESTDIR}/bin/sh
initrd.img correctly has /bin/sh being a symlink to /bin/busybox
binary, the latter being a copy of system /bin/busybox binary.
But next klibc hook is called:
ln -s /usr/lib/klibc/bin/* ${DESTDIR}/bin
ln -s /lib/klibc-*.so ${DESTDIR}/lib
The problem lies in the first line: indeed, system /usr/lib/klibc/bin
directory _contains_ a sh binary. But since busybox hook already
created a symlink with the same name /bin/sh in initrd.img, system
/usr/lib/klib/bin/sh binary can't be copied over the /bin/sh symlink,
hence the ln error on the console.
Now, why is this error disappearing with initramfs-tools 0.99 and why
is the generated initrd.img unbootable?
Since maximilian commit, busybox hook now executes:
rm -f ${DESTDIR}/bin/sh
rm -f ${DESTDIR}/bin/busybox
copy_exec ${BUSYBOXDIR}/busybox /bin/sh
System /bin/busybox binary is thus copied as /bin/sh binary into initrd.img.
But then, klibc hook is called:
cp -pL /usr/lib/klibc/bin/* ${DESTDIR}/bin
cp -pL /lib/klibc-*.so ${DESTDIR}/lib
The problem still lies in the first line, but since these are no more
symlinks but file copies, (i) /bin/sh binary in initrd.img is
overwritten with system /usr/lib/klibc/bin/sh binary and (ii) there's
obviously no more ln error.
I've looked at current initramfs-tools git repository. The problem is
still there, with a subtle difference.
Now, busybox hook executes:
rm -f ${DESTDIR}/bin/sh
rm -f ${DESTDIR}/bin/busybox
copy_exec ${BUSYBOXDIR}/busybox /bin/busybox
ln -s busybox ${DESTDIR}/bin/sh
A copy of system /bin/busybox binary is thus put into initrd.img, with
a /bin/sh symlink pointing to it.
However, klibc hook still runs:
cp -pL /usr/lib/klibc/bin/* ${DESTDIR}/bin
cp -pL /lib/klibc-*.so ${DESTDIR}/lib
Because of system /usr/lib/klibc/bin/sh binary, this ends up by
overwriting the _target_ of /bin/sh (symlink previously created by
busybox hook), thus replacing /bin/busybox binary in initrd.img by
system /usr/lib/klibc/bin/sh binary, making initrd.img unbootable.
I've checked that simply replacing /bin/busybox binary in initrd.img
(being in fact a copy of system /usr/lib/klibc/bin/sh binary) by real
system /bin/busybox binary solves the issue.
Now, how to fix this properly? I haven't found where the hook calls
ordering is done. But busybox hook definitely has to be called _after_
klibc one.
I don't know for the other Debian architectures, but if busybox hook
is also called _before_ klibc one, then all the initrd.img are either
wrong (at the best, since /bin/sh binary is thus not a copy of or a
symlink to system /bin/busybox binary as it should) or broken as on
ia64.
Émeric
Reply to: