I've prepared an NMU to fix this issue.  Attached is the debdiff.  Note
that I also had to fix the FTBFS, bug #602312.

I'm going to look for a sponsor to upload this, but if you want to
take care of it yourselff, that won't be necessary:
http://mentors.debian.net/debian/pool/main/i/isc-dhcp

Note that this is a high urgency security issue.

Best wishes,
Mike
diff -u isc-dhcp-4.1.1-P1/debian/changelog isc-dhcp-4.1.1-P1/debian/changelog
--- isc-dhcp-4.1.1-P1/debian/changelog
+++ isc-dhcp-4.1.1-P1/debian/changelog
@@ -1,3 +1,12 @@
+isc-dhcp (4.1.1-P1-16.1) unstable; urgency=high
+
+  * Non-maintainer upload.
+  * Fix cve-2011-0997: remote code execution vulnerability in dhclient
+    (closes: #621099).
+  * Fix ftbfs with 'ld --no-as-needed' (closes: #602312).
+
+ -- Michael Gilbert <michael.s.gilb...@gmail.com>  Sat, 09 Apr 2011 10:57:14 -0400
+
 isc-dhcp (4.1.1-P1-16) unstable; urgency=high
 
   * Patch by Raphael Geissert from 4.1-ESV for CVE-2011-0413 (closes: #611217)
diff -u isc-dhcp-4.1.1-P1/debian/patches/00list isc-dhcp-4.1.1-P1/debian/patches/00list
--- isc-dhcp-4.1.1-P1/debian/patches/00list
+++ isc-dhcp-4.1.1-P1/debian/patches/00list
@@ -13,6 +13,7 @@
 CVE-2010-3611
 # Ported from 4.1-ESV
 CVE-2011-0413
+CVE-2011-0997
 
 # must be applied before the LDAP stuff
 no-libcrypto
diff -u isc-dhcp-4.1.1-P1/debian/patches/dhcp-4.1.0-ldap-code.dpatch isc-dhcp-4.1.1-P1/debian/patches/dhcp-4.1.0-ldap-code.dpatch
--- isc-dhcp-4.1.1-P1/debian/patches/dhcp-4.1.0-ldap-code.dpatch
+++ isc-dhcp-4.1.1-P1/debian/patches/dhcp-4.1.0-ldap-code.dpatch
@@ -2754,7 +2754,7 @@
 diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' isc-dhcp-4.1.1-P1~/configure.ac isc-dhcp-4.1.1-P1/configure.ac
 --- isc-dhcp-4.1.1-P1~/configure.ac	2010-10-20 22:14:33.694570303 +0100
 +++ isc-dhcp-4.1.1-P1/configure.ac	2010-10-20 22:17:15.682086336 +0100
-@@ -419,6 +419,74 @@
+@@ -419,6 +419,75 @@
  # Look for optional headers.
  AC_CHECK_HEADERS(sys/socket.h net/if_dl.h net/if6.h regex.h)
  
@@ -2775,6 +2775,7 @@
 +	AC_SEARCH_LIBS([ber_init], [ldap], [
 +		LDAP_LIBS="-lldap"
 +	],[
++               AS_UNSET([ac_cv_search_ber_init])
 +		AC_SEARCH_LIBS([ber_init], [lber], [
 +			LDAP_LIBS="-lldap -llber"
 +		], [
only in patch2:
unchanged:
--- isc-dhcp-4.1.1-P1.orig/debian/patches/CVE-2011-0997.dpatch
+++ isc-dhcp-4.1.1-P1/debian/patches/CVE-2011-0997.dpatch
@@ -0,0 +1,232 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## All lines beginning with `## DP:' are a description of the patch.
+## CVE-2011-0997.dpatch by Michael Gilbert <michael.s.gilb...@gmail.com>
+
+@DPATCH@
+diff -pruN dhcp-4.1.1-P1.orig/client/dhclient.c dhcp-4.1.1-P1/client/dhclient.c
+--- dhcp-4.1.1-P1.orig/client/dhclient.c	2011-03-31 12:33:22.715696085 +0000
++++ dhcp-4.1.1-P1/client/dhclient.c	2011-03-31 12:36:42.451695492 +0000
+@@ -104,6 +104,11 @@ static void usage(void);
+ 
+ static isc_result_t write_duid(struct data_string *duid);
+ 
++static int check_domain_name(const char *ptr, size_t len, int dots);
++static int check_domain_name_list(const char *ptr, size_t len, int dots);
++static int check_option_values(struct universe *universe, unsigned int opt,
++			       const char *ptr, size_t len);
++
+ int
+ main(int argc, char **argv) {
+ 	int fd;
+@@ -3402,13 +3407,23 @@ void client_option_envadd (struct option
+ 		if (data.len) {
+ 			char name [256];
+ 			if (dhcp_option_ev_name (name, sizeof name,
+-						 oc -> option)) {
+-				client_envadd (es -> client, es -> prefix,
+-					       name, "%s",
+-					       (pretty_print_option
+-						(oc -> option,
+-						 data.data, data.len,
+-						 0, 0)));
++						 oc->option)) {
++				const char *value;
++				value = pretty_print_option(oc->option,
++							    data.data,
++							    data.len, 0, 0);
++				size_t length = strlen(value);
++
++				if (check_option_values(oc->option->universe,
++							oc->option->code,
++							value, length) == 0) {
++					client_envadd(es->client, es->prefix,
++						      name, "%s", value);
++				} else {
++					log_error("suspect value in %s "
++						  "option - discarded",
++						  name);
++				}
+ 				data_string_forget (&data, MDL);
+ 			}
+ 		}
+@@ -3486,12 +3501,32 @@ void script_write_params (client, prefix
+ 		data_string_forget (&data, MDL);
+ 	}
+ 
+-	if (lease -> filename)
+-		client_envadd (client,
+-			       prefix, "filename", "%s", lease -> filename);
+-	if (lease -> server_name)
+-		client_envadd (client, prefix, "server_name",
+-			       "%s", lease -> server_name);
++	if (lease->filename) {
++		if (check_option_values(NULL, DHO_ROOT_PATH,
++					lease->filename,
++					strlen(lease->filename)) == 0) {
++			client_envadd(client, prefix, "filename",
++				      "%s", lease->filename);
++		} else {
++			log_error("suspect value in %s "
++				  "option - discarded",
++				  "filename");
++		}
++	}
++
++	if (lease->server_name) {
++		if (check_option_values(NULL, DHO_HOST_NAME,
++					lease->server_name,
++					strlen(lease->server_name)) == 0 ) {
++			client_envadd (client, prefix, "server_name",
++				       "%s", lease->server_name);
++		} else {
++			log_error("suspect value in %s "
++				  "option - discarded",
++				  "server_name");
++		}
++	}
++				
+ 
+ 	for (i = 0; i < lease -> options -> universe_count; i++) {
+ 		option_space_foreach ((struct packet *)0, (struct lease *)0,
+@@ -4215,3 +4250,128 @@ dhcpv4_client_assignments(void)
+ 	} else
+ 		remote_port = htons (ntohs (local_port) - 1);   /* XXX */
+ }
++
++/*
++ * The following routines are used to check that certain
++ * strings are reasonable before we pass them to the scripts.
++ * This avoids some problems with scripts treating the strings
++ * as commands - see ticket 23722
++ * The domain checking code should be done as part of assembling
++ * the string but we are doing it here for now due to time
++ * constraints.
++ */
++
++static int check_domain_name(const char *ptr, size_t len, int dots)
++{
++	const char *p;
++
++	/* not empty or complete length not over 255 characters   */
++	if ((len == 0) || (len > 256))
++		return(-1);
++
++	/* consists of [[:alnum:]-]+ labels separated by [.]      */
++	/* a [_] is against RFC but seems to be "widely used"...  */
++	for (p=ptr; (*p != 0) && (len-- > 0); p++) {
++		if ((*p == '-') || (*p == '_')) {
++			/* not allowed at begin or end of a label */
++			if (((p - ptr) == 0) || (len == 0) || (p[1] == '.'))
++				return(-1);
++		} else if (*p == '.') {
++			/* each label has to be 1-63 characters;
++			   we allow [.] at the end ('foo.bar.')   */
++			size_t d = p - ptr;
++			if ((d <= 0) || (d >= 64))
++				return(-1);
++			ptr = p + 1; /* jump to the next label    */
++			if ((dots > 0) && (len > 0))
++				dots--;
++		} else if (isalnum((unsigned char)*p) == 0) {
++			/* also numbers at the begin are fine     */
++			return(-1);
++		}
++	}
++	return(dots ? -1 : 0);
++}
++
++static int check_domain_name_list(const char *ptr, size_t len, int dots)
++{
++	const char *p;
++	int ret = -1; /* at least one needed */
++
++	if ((ptr == NULL) || (len == 0))
++		return(-1);
++
++	for (p=ptr; (*p != 0) && (len > 0); p++, len--) {
++		if (*p != ' ')
++			continue;
++		if (p > ptr) {
++			if (check_domain_name(ptr, p - ptr, dots) != 0)
++				return(-1);
++			ret = 0;
++		}
++		ptr = p + 1;
++	}
++	if (p > ptr)
++		return(check_domain_name(ptr, p - ptr, dots));
++	else
++		return(ret);
++}
++
++static int check_option_values(struct universe *universe,
++			       unsigned int opt,
++			       const char *ptr,
++			       size_t len)
++{
++	if (ptr == NULL)
++		return(-1);
++
++	/* just reject options we want to protect, will be escaped anyway */
++	if ((universe == NULL) || (universe == &dhcp_universe)) {
++		switch(opt) {
++		      case DHO_HOST_NAME:
++		      case DHO_NIS_DOMAIN:
++		      case DHO_NETBIOS_SCOPE:
++			return check_domain_name(ptr, len, 0);
++			break;
++		      case DHO_DOMAIN_NAME: /* accept a list for compatibiliy */
++		      case DHO_DOMAIN_SEARCH:
++			return check_domain_name_list(ptr, len, 0);
++			break;
++		      case DHO_ROOT_PATH:
++			if (len == 0)
++				return(-1);
++			for (; (*ptr != 0) && (len-- > 0); ptr++) {
++				if(!(isalnum((unsigned char)*ptr) ||
++				     *ptr == '#'  || *ptr == '%' ||
++				     *ptr == '+'  || *ptr == '-' ||
++				     *ptr == '_'  || *ptr == ':' ||
++				     *ptr == '.'  || *ptr == ',' ||
++				     *ptr == '@'  || *ptr == '~' ||
++				     *ptr == '\\' || *ptr == '/' ||
++				     *ptr == '['  || *ptr == ']' ||
++				     *ptr == '='  || *ptr == ' '))
++					return(-1);
++			}
++			return(0);
++			break;
++		}
++	}
++
++#ifdef DHCPv6
++	if (universe == &dhcpv6_universe) {
++		switch(opt) {
++		      case D6O_SIP_SERVERS_DNS:
++		      case D6O_DOMAIN_SEARCH:
++		      case D6O_NIS_DOMAIN_NAME:
++		      case D6O_NISP_DOMAIN_NAME:
++			return check_domain_name_list(ptr, len, 0);
++			break;
++		}
++	}
++#endif
++
++	return(0);
++}
++ 
++
++
+diff -pruN dhcp-4.1.1-P1.orig/common/options.c dhcp-4.1.1-P1/common/options.c
+--- dhcp-4.1.1-P1.orig/common/options.c	2009-07-23 19:02:09.000000000 +0000
++++ dhcp-4.1.1-P1/common/options.c	2011-03-31 12:36:42.453695760 +0000
+@@ -3907,7 +3907,8 @@ pretty_escape(char **dst, char *dend, co
+ 				count += 4;
+ 			}
+ 		} else if (**src == '"' || **src == '\'' || **src == '$' ||
+-			   **src == '`' || **src == '\\') {
++			   **src == '`' || **src == '\\' || **src == '|' ||
++			   **src == '&') {
+ 			if (*dst + 2 > dend)
+ 				return -1;
+ 

Reply via email to