Subject: [PATCH 5/5] Check for init scripts not testing before sourcing /etc/default files

From: Raphael Geissert <[email-masked]>
Date: Wed, 17 Jun 2009 08:29:26 -0500

Init scripts not making sure the /etc/default file exists are very likely
to break in the event the administrator deletes one or more files, which is
allowed by policy.
---
 checks/init.d                                      |    9 ++++++
 checks/init.d.desc                                 |   10 ++++++
 t/tests/init.d-general/debian/debian/control.in    |   11 +++++++
 .../init.d-general-sourcing-without-test.init      |   30 ++++++++++++++++++++
 t/tests/init.d-general/tags                        |    1 +
 5 files changed, 61 insertions(+), 0 deletions(-)
 create mode 100644 t/tests/init.d-general/debian/debian/init.d-general-sourcing-without-test.init

diff --git a/checks/init.d b/checks/init.d
index c2dd98a..43ba9d9 100644
--- a/checks/init.d
+++ b/checks/init.d
@@ -176,6 +176,7 @@ sub checkinit {
     open(IN, '<', $initd_file)
 	or fail("cannot open init.d file $initd_file: $!");
     my (%tag, %lsb);
+    my $in_file_test = 0;
     while (defined(my $l = <IN>)) {
 	if ($. eq 1 && $l =~ m,^#!\s*(/usr/[^\s]+),) {
 	    tag "init.d-script-uses-usr-interpreter", "/etc/init.d/$_ $1";
@@ -216,6 +217,14 @@ sub checkinit {
 	    }
 	}
 
+	# Pretty dummy way to handle conditionals, but should be enough
+	# for simple init scripts
+	$in_file_test = 1 if ($l =~ m/\bif\s+.+?[\s+-[fe]\s+/);
+	$in_file_test = 0 if ($l =~ m/\bfi\b/);
+	if (!$in_file_test && $l =~ m,^\s*\.\s+["'"]?(/etc/default/[\$\w/-]+),) {
+	    tag "init.d-script-sourcing-without-test", "/etc/init.d/$_:$. $1";
+	}
+
 	while ($l =~ s/^[^#]*?(start|stop|restart|force-reload)//o) {
 	    $tag{$1} = 1;
 	}
diff --git a/checks/init.d.desc b/checks/init.d.desc
index a960da9..3131960 100644
--- a/checks/init.d.desc
+++ b/checks/init.d.desc
@@ -213,3 +213,13 @@ Info: The given <tt>/etc/init.d</tt> script specifies an interpreter in
  Another case where the script might fail to execute is early during the boot
  process, when the <tt>/usr</tt> partition might not yet be mounted by the time
  the script needs its interpreter.
+
+Tag: init.d-script-sourcing-without-test
+Severity: important
+Certainty: possible
+Info: The given <tt>/etc/init.d</tt> script seems to be sourcing an
+ <tt>/etc/default/</tt> file without assuring its existence first.
+ .
+ Files in <tt>/etc/default/</tt> can be deleted by the administrator at any
+ time and the init script should handle the situation gracefully.
+Ref: policy 9.3.2
diff --git a/t/tests/init.d-general/debian/debian/control.in b/t/tests/init.d-general/debian/debian/control.in
index 7d2d840..fb87297 100644
--- a/t/tests/init.d-general/debian/debian/control.in
+++ b/t/tests/init.d-general/debian/debian/control.in
@@ -32,3 +32,14 @@ Description: {$description} -- bad script interpreter
  This is a test package designed to exercise some feature or tag of
  Lintian.  It is part of the Lintian test suite and may do very odd
  things.  It should not be installed like a regular package.
+
+Package: {$srcpkg}-sourcing-without-test
+Architecture: {$architecture}
+Depends: $\{shlibs:Depends\}, $\{misc:Depends\}
+Description: {$description} -- sourcing without test
+ Test a check for . /etc/default/foo without checking the existance of
+ the file beforehand.
+ .
+ This is a test package designed to exercise some feature or tag of
+ Lintian.  It is part of the Lintian test suite and may do very odd
+ things.  It should not be installed like a regular package.
diff --git a/t/tests/init.d-general/debian/debian/init.d-general-sourcing-without-test.init b/t/tests/init.d-general/debian/debian/init.d-general-sourcing-without-test.init
new file mode 100644
index 0000000..cc0e77d
--- /dev/null
+++ b/t/tests/init.d-general/debian/debian/init.d-general-sourcing-without-test.init
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+
+### BEGIN INIT INFO
+# Provides:          foo
+# Required-Start:    $remote_fs
+# Required-Stop:     $remote_fs
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+echo start stop reload restart force-reload status
+
+. /etc/default/rcS
+
+[ ! -f /etc/default/foo ] || . /etc/default/foo
+
+[ -f /etc/default/bar ] && . /etc/default/bar
+
+if [ -f /etc/default/moo ]; then
+    . /etc/default/moo
+fi
+
+PACKAGE=moo
+[ -f /etc/default/$PACKAGE ] && . /etc/default/$PACKAGE
+
+if [ -f /etc/default/$PACKAGE ]; then
+    . /etc/default/$PACKAGE
+fi
diff --git a/t/tests/init.d-general/tags b/t/tests/init.d-general/tags
index d52d0c7..e13c89a 100644
--- a/t/tests/init.d-general/tags
+++ b/t/tests/init.d-general/tags
@@ -3,3 +3,4 @@ E: init.d-general-bugs: init.d-script-does-not-implement-required-option /etc/in
 E: init.d-general-bugs: init.d-script-does-not-implement-required-option /etc/init.d/init.d-general-bugs start
 E: init.d-general-bugs: init.d-script-does-not-implement-required-option /etc/init.d/init.d-general-bugs stop
 E: init.d-general-interpreter-in-usr-dir: init.d-script-uses-usr-interpreter /etc/init.d/init.d-general-interpreter-in-usr-dir /usr/bin/perl
+E: init.d-general-sourcing-without-test: init.d-script-sourcing-without-test /etc/init.d/init.d-general-sourcing-without-test:15 /etc/default/rcS
-- 
1.6.3.1