[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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
 	cat > /target/sbin/start-stop-daemon <<EOF
@@ -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
 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
 	# 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
 	# Undo the mounts done by the packages during installation.

Colin Watson                                       [cjwatson@ubuntu.com]

Reply to: