Bug#654580: di-utils: needs to divert start-stop-daemon and initctl rather than simply moving them
Package: di-utils
Version: 1.87
Severity: grave
Tags: patch
User: ubuntu-devel@lists.ubuntu.com
Usertags: origin-ubuntu ubuntu-patch precise
In https://launchpad.net/bugs/900526, we discovered a serious problem
with the way chroot-setup.sh deals with start-stop-daemon and initctl.
The chroot_setup function moves these programs aside, replacing them
with temporary fake versions, and the chroot_cleanup* functions put them
back. However, they do not use dpkg diversions to do so. As a quite
plausible example, if pkgsel applies an update to dpkg,
start-stop-daemon will be moved aside at the start, but the dpkg upgrade
will write a new version of /sbin/start-stop-daemon, and then the
original binary will be moved back at the end. This means: (a) after
dpkg is unpacked the chroot is no longer safe against daemons being
started; (b) the resulting system will claim to have the new dpkg
version but will in fact have the old start-stop-daemon binary!
We actually noticed this with initctl, which is part of upstart, so that
wouldn't happen in typical Debian installs, but the start-stop-daemon
example might well do. Although I can't find a specific reference, I've
definitely seen people turning up with odd symptoms related to
start-stop-daemon in the past which were never fully diagnosed, and I
strongly suspect that some of those were due to this bug.
I intend to apply this patch, which fixes this bug in my tests.
diff --git a/chroot-setup.sh b/chroot-setup.sh
index 733026e..4b98529 100644
--- a/chroot-setup.sh
+++ b/chroot-setup.sh
@@ -25,6 +25,15 @@ update_mtab() {
done ) > $mtab
}
+divert () {
+ chroot /target dpkg-divert --add --divert "$1.REAL" --rename "$1"
+}
+
+undivert () {
+ rm -f "/target$1"
+ chroot /target dpkg-divert --remove --rename "$1"
+}
+
chroot_setup () {
# Bail out if directories we need are not there
if [ ! -d /target/sbin ] || [ ! -d /target/usr/sbin ] || \
@@ -55,7 +64,7 @@ EOF
chmod a+rx /target/usr/sbin/policy-rc.d
if [ -e /target/sbin/start-stop-daemon ]; then
- mv /target/sbin/start-stop-daemon /target/sbin/start-stop-daemon.REAL
+ divert /sbin/start-stop-daemon
fi
cat > /target/sbin/start-stop-daemon <<EOF
#!/bin/sh
@@ -67,7 +76,7 @@ EOF
# If Upstart is in use, add a dummy initctl to stop it starting jobs.
if [ -x /target/sbin/initctl ]; then
- mv /target/sbin/initctl /target/sbin/initctl.REAL
+ divert /sbin/initctl
cat > /target/sbin/initctl <<EOF
#!/bin/sh
echo 1>&2
@@ -165,9 +174,9 @@ EOF
chroot_cleanup () {
rm -f /target/usr/sbin/policy-rc.d
- mv /target/sbin/start-stop-daemon.REAL /target/sbin/start-stop-daemon
+ undivert /sbin/start-stop-daemon
if [ -x /target/sbin/initctl.REAL ]; then
- mv /target/sbin/initctl.REAL /target/sbin/initctl
+ undivert /sbin/initctl
fi
# Undo the mounts done by the packages during installation.
@@ -188,9 +197,9 @@ chroot_cleanup () {
# Variant of chroot_cleanup that only cleans up chroot_setup's mounts.
chroot_cleanup_localmounts () {
rm -f /target/usr/sbin/policy-rc.d
- mv /target/sbin/start-stop-daemon.REAL /target/sbin/start-stop-daemon
+ undivert /sbin/start-stop-daemon
if [ -x /target/sbin/initctl.REAL ]; then
- mv /target/sbin/initctl.REAL /target/sbin/initctl
+ undivert /sbin/initctl
fi
# Undo the mounts done by the packages during installation.
--
Colin Watson [cjwatson@ubuntu.com]
Reply to: