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; +