diff --git a/dhcp-4.2.1-P1-dhclient-option-checks.bnc675052.diff b/dhcp-4.2.1-P1-dhclient-option-checks.bnc675052.diff new file mode 100644 index 0000000..f4210ee --- /dev/null +++ b/dhcp-4.2.1-P1-dhclient-option-checks.bnc675052.diff @@ -0,0 +1,77 @@ +From 7c0b7ae289a0f25853bd4bb660f3dd34b5c1ce88 Mon Sep 17 00:00:00 2001 +From: Marius Tomaschewski +Date: Wed, 27 Apr 2011 13:56:47 +0200 +Subject: [PATCH] dhclient string option checks + +Merged dhclient pretty escape and string option checks. +Use relaxed domain-name option check causing a regression, when the +server is misusing it to provide a domain list and does not provide +it via the domain-search option; pretty escape semicolon as well +(bnc#675052, CVE-2011-0997). + +Signed-off-by: Marius Tomaschewski +--- + client/dhclient.c | 8 ++++---- + common/options.c | 2 +- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/client/dhclient.c b/client/dhclient.c +index 970b935..93db494 100644 +--- a/client/dhclient.c ++++ b/client/dhclient.c +@@ -3142,7 +3142,7 @@ void script_write_params (client, prefix, lease) + } else { + log_error("suspect value in %s " + "option - discarded", +- lease->filename); ++ "filename"); + } + } + +@@ -3155,7 +3155,7 @@ void script_write_params (client, prefix, lease) + } else { + log_error("suspect value in %s " + "option - discarded", +- lease->server_name); ++ "server-name"); + } + } + +@@ -4077,7 +4077,7 @@ 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)) ++ if ((len == 0) || (len >= 256)) + return(-1); + + /* consists of [[:alnum:]-]+ labels separated by [.] */ +@@ -4140,11 +4140,11 @@ static int check_option_values(struct universe *universe, + if ((universe == NULL) || (universe == &dhcp_universe)) { + switch(opt) { + case DHO_HOST_NAME: +- case DHO_DOMAIN_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; +diff --git a/common/options.c b/common/options.c +index c26f88c..8b4be65 100644 +--- a/common/options.c ++++ b/common/options.c +@@ -3916,7 +3916,7 @@ pretty_escape(char **dst, char *dend, const unsigned char **src, + } + } else if (**src == '"' || **src == '\'' || **src == '$' || + **src == '`' || **src == '\\' || **src == '|' || +- **src == '&') { ++ **src == '&' || **src == ';') { + if (*dst + 2 > dend) + return -1; + +-- +1.7.3.4 + diff --git a/dhcp-4.2.1-P1.tar.bz2 b/dhcp-4.2.1-P1.tar.bz2 new file mode 100644 index 0000000..b0e4b27 --- /dev/null +++ b/dhcp-4.2.1-P1.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb8e19d01c5ab5de1da759c3fb34e4967e863e78c8d6106d2cbb0ffeaa80df76 +size 8659247 diff --git a/dhcp-4.2.1-dhclient-option-checks.bnc675052.diff b/dhcp-4.2.1-dhclient-option-checks.bnc675052.diff deleted file mode 100644 index 99d948b..0000000 --- a/dhcp-4.2.1-dhclient-option-checks.bnc675052.diff +++ /dev/null @@ -1,248 +0,0 @@ -From 632c8ceeff26a7663f939895f77aecb8377773f2 Mon Sep 17 00:00:00 2001 -From: Marius Tomaschewski -Date: Sun, 27 Mar 2011 13:15:58 +0200 -Subject: [PATCH] dhclient: discard incorrect string options - -Discard string options such as host and domain names -containing disallowed characters or beeing too long. -This proctive patch limits root-path to the a-zA-Z0-9, -space and the #%+-_:.,@~/\[]= characters. - -Signed-off-by: Marius Tomaschewski ---- - client/dhclient.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++++---- - common/options.c | 3 +- - 2 files changed, 175 insertions(+), 14 deletions(-) - -diff --git a/client/dhclient.c b/client/dhclient.c -index dc19e8b..5d96c72 100644 ---- a/client/dhclient.c -+++ b/client/dhclient.c -@@ -91,6 +91,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; -@@ -3034,13 +3039,23 @@ void client_option_envadd (struct option_cache *oc, - 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); - } - } -@@ -3118,12 +3133,32 @@ void script_write_params (client, prefix, lease) - 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, -@@ -4026,3 +4061,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_DOMAIN_NAME: -+ case DHO_NIS_DOMAIN: -+ case DHO_NETBIOS_SCOPE: -+ return check_domain_name(ptr, len, 0); -+ break; -+ 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 --git a/common/options.c b/common/options.c -index 28c36e6..3a6cb33 100644 ---- a/common/options.c -+++ b/common/options.c -@@ -3915,7 +3915,8 @@ pretty_escape(char **dst, char *dend, const unsigned char **src, - count += 4; - } - } else if (**src == '"' || **src == '\'' || **src == '$' || -- **src == '`' || **src == '\\') { -+ **src == '`' || **src == '\\' || **src == '|' || -+ **src == '&' || **src == ';') { - if (*dst + 2 > dend) - return -1; - --- -1.7.3.4 - diff --git a/dhcp-4.2.1.tar.bz2 b/dhcp-4.2.1.tar.bz2 deleted file mode 100644 index 09becf6..0000000 --- a/dhcp-4.2.1.tar.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:172851e0eedbbb009142b143a5f1ed9d6d370d909475a356ac9a753c15c354e9 -size 8656089 diff --git a/dhcp.changes b/dhcp.changes index 0423d76..1e67e36 100644 --- a/dhcp.changes +++ b/dhcp.changes @@ -1,3 +1,13 @@ +------------------------------------------------------------------- +Wed Apr 27 12:31:25 UTC 2011 - mt@suse.de + +- Updated to ISC dhcp-4.2.1-P1 release, that provides most of the + dhclient pretty escape and string option checks. Merged to use + relaxed domain-name option check causing a regression, when the + server is misusing it to provide a domain list (compatibility to + attic clients) and does not provide it via domain-search option; + pretty escape semicolon as well (bnc#675052, CVE-2011-0997). + ------------------------------------------------------------------- Thu Mar 31 09:56:02 UTC 2011 - mt@suse.de diff --git a/dhcp.spec b/dhcp.spec index 47693d3..5f0350e 100644 --- a/dhcp.spec +++ b/dhcp.spec @@ -17,7 +17,7 @@ # norootforbuild -%define isc_version 4.2.1 +%define isc_version 4.2.1-P1 %define susefw2dir %{_sysconfdir}/sysconfig/SuSEfirewall2.d/services %define omc_prefix /usr/share/omc %define omc_svcdir %{omc_prefix}/svcinfo.d @@ -35,8 +35,8 @@ BuildRequires: dos2unix License: BSD3c(or similar) Group: Productivity/Networking/Boot/Servers AutoReqProv: on -Version: 4.2.1 -Release: 1 +Version: 4.2.1.P1 +Release: 0 Summary: Common Files Used by ISC DHCP Software Url: http://www.isc.org/software/dhcp Source0: dhcp-%{isc_version}.tar.bz2 @@ -82,7 +82,7 @@ Patch30: dhcp-4.2.1-ldap-patch-mt01.diff.bz2 Patch40: dhcp-4.1.1-P1-lpf-bind-msg-fix.diff Patch41: dhcp-4.1.1-P1-relay-no-ip-on-interface.diff Patch44: dhcp-4.2.0-xen-checksum.patch -Patch45: dhcp-4.2.1-dhclient-option-checks.bnc675052.diff +Patch45: dhcp-4.2.1-P1-dhclient-option-checks.bnc675052.diff ## PreReq: /bin/touch /sbin/chkconfig sysconfig BuildRoot: %{_tmppath}/%{name}-%{version}-build