Package: bind9
Version: 1:9.7.1.dfsg.P2-2
Priority: normal
Tags: patch

Currently, bind9 does not try to take any precaution when handling 'include'
statements in the config files. It will happily accept even an include
statement in a file pointing to itself which is, obviously, something that
leads nowhere. For example, see attached named.conf.local, which bind9 tries
to chew even if it doesn't make sense.

Fortunately, 9.7.1 (unlike 9.6) will end up dying due to it trying to open
too many files, however, in the meantime, it chews up all the available
memory in the system and the message that it outputs does not indicate where
the error is. For reference, see attached 'too-many-open-files.log' based on
using the above named.conf.local in a stock Debian bind9 package.

It would be better if bind9 checked this limit while parsing the
configuration files, in order to detect the issue and report it properly. I
have developed a patch (attached as file
'bind9-9.7.1.dfsg.P2-parselimit.diff') that tries to handle this issue. It
could be even improved to detect the obvious errors of including a file
within the same file (which leads to bind recursively trying to open the same
file).

With the above patch the error produced by bind9 is much more clarifying and,
due to early detection, the bind9 server does not get to chew up all the
memory before it dies due to openining up too many descriptors. For reference
see the attached log  'limit-recursive-include.log'

I'm flagging this bug as normal since, in this version, bind9 does actually
manage to get hold of himself. Unfortunately, in the lenny version
(1:9.6.ESV.R1+dfsg-0+lenny2) the same configuration leads to the named
process eating up all the available memory until either a) it grinds the
server to a halt or b) the kernel kills it through its out of memory killer.

And, yes, I found this the hard way in a lenny server in which a
misconfiguration brought the server to a halt by consuming all of its
available memory.

I would appreciate if you would consider this patch for bind9 and forward it
upstream for their consideration.


Regards

Javier

PS: All logs have been generated running 'named -u bind -g' 
//
// Do any local configuration here
//

// Consider adding the 1918 zones here, if they are not used in your
// organization
//include "/etc/bind/zones.rfc1918";


include "/etc/bind/named.conf.local";

28-Sep-2010 20:51:51.919 starting BIND 9.7.1-P2 -u bind -g
28-Sep-2010 20:51:51.919 built with '--prefix=/usr' '--mandir=/usr/share/man' 
'--infodir=/usr/share/info' '--sysconfdir=/etc/bind' '--localstatedir=/var' 
'--enable-threads' '--enable-largefile' '--with-libtool' '--enable-shared' 
'--enable-static' '--with-openssl=/usr' '--with-gssapi=/usr' '--with-gnu-ld' 
'--with-dlz-postgres=no' '--with-dlz-mysql=no' '--with-dlz-bdb=yes' 
'--with-dlz-filesystem=yes' '--with-dlz-ldap=yes' '--with-dlz-stub=yes' 
'--with-geoip=/usr' '--enable-ipv6' 'CFLAGS=-fno-strict-aliasing -DDIG_SIGCHASE 
-O2' 'LDFLAGS=' 'CPPFLAGS='
28-Sep-2010 20:51:51.919 adjusted limit on open files from 1024 to 1048576
28-Sep-2010 20:51:51.919 found 2 CPUs, using 2 worker threads
28-Sep-2010 20:51:51.920 using up to 4096 sockets
28-Sep-2010 20:51:51.925 loading configuration from '/etc/bind/named.conf'
28-Sep-2010 20:51:54.933 /etc/bind/named.conf.local:10: open: 
/etc/bind/named.conf.local: too many open files
28-Sep-2010 20:51:55.731 loading configuration: too many open files
28-Sep-2010 20:51:55.731 exiting (due to fatal error)
diff -Nru bind9-9.7.1.dfsg.P2/debian/changelog bind9-9.7.1.dfsg.P2-parselimit/debian/changelog
--- bind9-9.7.1.dfsg.P2/debian/changelog	2010-07-16 13:25:16.000000000 +0200
+++ bind9-9.7.1.dfsg.P2-parselimit/debian/changelog	2010-09-28 19:21:25.000000000 +0200
@@ -1,3 +1,12 @@
+bind9 (1:9.7.1.dfsg.P2-3) unstable; urgency=low
+
+  * /lib/isccfg/include/isccfg/grammar.h, lib/isccfg/parser.c:
+    Limit the maximum number of include files that can be opened
+    simultaneously to prevent recursive includes (i.e. named.conf
+    with an 'include named.conf' statement) from working.
+
+ -- Javier Fernandez-Sanguino Pen~a <j...@debian.org>  Tue, 28 Sep 2010 19:19:16 +0200
+
 bind9 (1:9.7.1.dfsg.P2-2) unstable; urgency=low
 
   * Correct conflicts for bind9-host
diff -Nru bind9-9.7.1.dfsg.P2/lib/isccfg/include/isccfg/grammar.h bind9-9.7.1.dfsg.P2-parselimit/lib/isccfg/include/isccfg/grammar.h
--- bind9-9.7.1.dfsg.P2/lib/isccfg/include/isccfg/grammar.h	2009-06-12 01:47:55.000000000 +0200
+++ bind9-9.7.1.dfsg.P2-parselimit/lib/isccfg/include/isccfg/grammar.h	2010-09-28 21:25:19.000000000 +0200
@@ -203,6 +203,14 @@
 	 */
 	cfg_obj_t *	closed_files;
 
+        /* %
+         * Number of files that we are currently
+         * parsing, this is the length of the open_files
+         * stack. We keep this number in order to 
+         * detect infinite recursive includes.
+         */
+	unsigned int	open_files_count;
+
 	/*%
 	 * Current line number.  We maintain our own
 	 * copy of this so that it is available even
diff -Nru bind9-9.7.1.dfsg.P2/lib/isccfg/parser.c bind9-9.7.1.dfsg.P2-parselimit/lib/isccfg/parser.c
--- bind9-9.7.1.dfsg.P2/lib/isccfg/parser.c	2009-09-03 01:43:54.000000000 +0200
+++ bind9-9.7.1.dfsg.P2-parselimit/lib/isccfg/parser.c	2010-09-28 21:25:19.000000000 +0200
@@ -395,6 +395,7 @@
 	pctx->errors = 0;
 	pctx->warnings = 0;
 	pctx->open_files = NULL;
+	pctx->open_files_count = 0;
 	pctx->closed_files = NULL;
 	pctx->line = 0;
 	pctx->callback = NULL;
@@ -432,12 +433,22 @@
 	return (result);
 }
 
+#define MAX_OPEN_FILES 100 /* How many open files we want to keep. */
+
 static isc_result_t
 parser_openfile(cfg_parser_t *pctx, const char *filename) {
 	isc_result_t result;
 	cfg_listelt_t *elt = NULL;
 	cfg_obj_t *stringobj = NULL;
 
+        /* Check wether the limit of open files has been exceeded */
+        pctx->open_files_count++;
+        if (pctx->open_files_count > MAX_OPEN_FILES)  {
+		cfg_parser_error(pctx, 0, "too many included files, last was: %s",
+			     filename);
+		goto cleanup;
+	}
+
 	result = isc_lex_openfile(pctx->lexer, filename);
 	if (result != ISC_R_SUCCESS) {
 		cfg_parser_error(pctx, 0, "open: %s: %s",
@@ -449,6 +460,7 @@
 	CHECK(create_listelt(pctx, &elt));
 	elt->obj = stringobj;
 	ISC_LIST_APPEND(pctx->open_files->value.list, elt, link);
+            
 
 	return (ISC_R_SUCCESS);
  cleanup:
@@ -2118,6 +2130,8 @@
 						value.list, elt, link);
 				ISC_LIST_APPEND(pctx->closed_files->
 						value.list, elt, link);
+                                if (pctx->open_files_count > 0) 
+                                    pctx->open_files_count--;
 				goto redo;
 			}
 			pctx->seen_eof = ISC_TRUE;
28-Sep-2010 20:45:43.768 starting BIND 9.7.1-P2 -u bind -g
28-Sep-2010 20:45:43.786 built with '--prefix=/usr' '--mandir=/usr/share/man' 
'--infodir=/usr/share/info' '--sysconfdir=/etc/bind' '--localstatedir=/var' 
'--enable-threads' '--enable-largefile' '--with-libtool' '--enable-shared' 
'--enable-static' '--with-openssl=/usr' '--with-gssapi=/usr' '--with-gnu-ld' 
'--with-dlz-postgres=no' '--with-dlz-mysql=no' '--with-dlz-bdb=yes' 
'--with-dlz-filesystem=yes' '--with-dlz-ldap=yes' '--with-dlz-stub=yes' 
'--with-geoip=/usr' '--enable-ipv6' 'CFLAGS=-fno-strict-aliasing -DDIG_SIGCHASE 
-O2' 'LDFLAGS=' 'CPPFLAGS='
28-Sep-2010 20:45:43.786 adjusted limit on open files from 1024 to 1048576
28-Sep-2010 20:45:43.786 found 2 CPUs, using 2 worker threads
28-Sep-2010 20:45:43.787 using up to 4096 sockets
28-Sep-2010 20:45:43.792 loading configuration from '/etc/bind/named.conf'
28-Sep-2010 20:45:43.796 /etc/bind/named.conf.local:10: too many included 
files, last was: /etc/bind/named.conf.local
28-Sep-2010 20:45:43.797 loading configuration: (result code text not available)
28-Sep-2010 20:45:43.797 exiting (due to fatal error)

Attachment: signature.asc
Description: Digital signature

Reply via email to