Hello community, here is the log from the commit of package dhcp for openSUSE:11.3 checked in at Wed Apr 6 10:54:44 CEST 2011.
-------- --- old-versions/11.3/UPDATES/all/dhcp/dhcp.changes 2011-02-01 16:20:13.000000000 +0100 +++ 11.3/dhcp/dhcp.changes 2011-04-06 10:34:31.000000000 +0200 @@ -1,0 +2,13 @@ +Wed Mar 30 10:16:31 UTC 2011 - [email protected] + +- Discard string options such as host and domain names containing + disallowed characters or beeing too long. This proctive patch + limits the root-path to a-zA-Z0-9, #%+-_:.,@~/\[]= and a space + (bnc#675052, CVE-2011-0997). +- Added patch to handle packets with xen partial UDP checksums + by David Cantrell (bnc#668194). +- dhclient-script: fixed typo causing that only global settings + to set hostname and default route were applied for primary + and never per interface settings (bnc#673792). + +------------------------------------------------------------------- calling whatdependson for 11.3-i586 New: ---- dhcp-4.1-ESV-R1-dhclient-option-checks.bnc675052.diff dhcp-4.1-ESV-R1-xen-checksum.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ dhcp.spec ++++++ --- /var/tmp/diff_new_pack.NzsZ42/_old 2011-04-06 10:53:58.000000000 +0200 +++ /var/tmp/diff_new_pack.NzsZ42/_new 2011-04-06 10:53:58.000000000 +0200 @@ -33,7 +33,7 @@ Group: Productivity/Networking/Boot/Servers AutoReqProv: on Version: 4.1.2.ESV.1 -Release: 0.<RELEASE2> +Release: 0.<RELEASE4> Summary: Common Files Used by ISC DHCP Software Url: http://www.isc.org/software/dhcp Source0: dhcp-%{isc_version}.tar.bz2 @@ -74,6 +74,7 @@ Patch13: dhcp-4.1.1-tmpfile.diff Patch20: dhcp-4.1.1-dhclient-exec-filedes.diff Patch21: dhcp-4.1-ESV-R1-dhclient-send-hostname-rml.diff +Patch22: dhcp-4.1-ESV-R1-dhclient-option-checks.bnc675052.diff ## patch lives here: http://www.suse.de/~mt/git/dhcp-ldap.git/ %if 0%{?with_ldap} Patch30: dhcp-4.1-ESV-R1-ldap-patch-mt-02.diff.bz2 @@ -81,6 +82,7 @@ Patch40: dhcp-4.1.1-P1-lpf-bind-msg-fix.diff Patch41: dhcp-4.1.1-P1-relay-no-ip-on-interface.diff Patch42: dhcp-4.1.1-P1-optional-value-infinite-loop.diff +Patch43: dhcp-4.1-ESV-R1-xen-checksum.patch ## PreReq: /bin/touch /sbin/chkconfig sysconfig BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -197,12 +199,14 @@ %patch13 -p1 %patch20 -p1 %patch21 -p1 +%patch22 -p1 %if 0%{?with_ldap} %patch30 -p1 %endif %patch40 -p1 %patch41 -p1 %patch42 -p1 +%patch43 -p1 ## find . -type f -name \*.cat\* -exec rm -f {} \; dos2unix contrib/ms2isc/* ++++++ dhclient-script ++++++ --- /var/tmp/diff_new_pack.NzsZ42/_old 2011-04-06 10:53:58.000000000 +0200 +++ /var/tmp/diff_new_pack.NzsZ42/_new 2011-04-06 10:53:58.000000000 +0200 @@ -236,21 +236,26 @@ } set_hostname() { + rx_host='^[[:alnum:]][[:alnum:]_-]{0,62}$' if [ "$DHCLIENT_SET_HOSTNAME" = yes ] ; then + new_host_name="${new_host_name%%.*}" + [[ ${new_host_name} =~ ${rx_host} ]] || unset new_host_name current_hostname=`hostname` - if [ "x${current_hostname%%.*}" = "x" ] || \ - [ "x${current_hostname%%.*}" = "x(none)" ] || \ - [ "x${current_hostname%%.*}" = "xlocalhost" ] || \ - [ "x${current_hostname%%.*}" != "x${new_host_name%%.*}" ]; then + current_hostname="${current_hostname%%.*}" + [[ ${current_hostname} =~ ${rx_host} ]] || unset current_hostname - if [ "x${new_host_name%%.*}" != "x" ]; then - hostname "${new_host_name%%.*}" + if [ "x${current_hostname}" = "x" ] || \ + [ "x${current_hostname}" = "xlocalhost" ] || \ + [ "x${current_hostname}" != "x${new_host_name}" ]; then + if [ "x${new_host_name}" != "x" ]; then + hostname "${new_host_name}" else if [ -x /usr/bin/host ] ; then if out=`host -W 2 "$new_ip_address" 2>/dev/null` ; then - _hostname="`echo "$out" | sed 's:^.* ::; s:\..*::'`" + _hostname="`echo "$out" | sed 's:^.* ::; s:\..*::; s:.*[)]::'`" + [[ ${_hostname} =~ ${rx_host} ]] || unset _hostname if [ "x${_hostname}" != "x" -a \ - "x${_hostname}" != "x${current_hostname%%.*}" ]; then + "x${_hostname}" != "x${current_hostname}" ]; then hostname "${_hostname}" fi fi @@ -264,7 +269,9 @@ # it changed, we've to handle it anyway... local OLD_HOSTNAME=`read_cached_config_data hostname $interface` local CUR_HOSTNAME=`hostname 2>/dev/null` - if test "x$OLD_HOSTNAME" != "x$CUR_HOSTNAME" ; then + CUR_HOSTNAME="${CUR_HOSTNAME%%.*}" + if [[ ${CUR_HOSTNAME} =~ ${rx_host} ]] && \ + [ "x$OLD_HOSTNAME" != "x$CUR_HOSTNAME" ] ; then write_cached_config_data hostname "$CUR_HOSTNAME" $interface commit_cached_config_data $interface @@ -310,7 +317,7 @@ then eval `grep --no-filename \ '^[[:space:]]*DHCLIENT_SET_\(HOSTNAME\|DEFAULT_ROUTE\)=' \ - "$SYSCONFIG_CFG_DIR/dhcp" + "$SYSCONFIG_CFG_DIR/dhcp" \ "$SYSCONFIG_CFG_DIR/ifcfg-${interface}" 2>/dev/null` else eval `grep --no-filename \ ++++++ dhcp-4.1-ESV-R1-dhclient-option-checks.bnc675052.diff ++++++ >From 022ebe7b2420257ab359e66deac2570faa3a2d5f Mon Sep 17 00:00:00 2001 From: Marius Tomaschewski <[email protected]> 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 <[email protected]> --- 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 45e9e1a..68f99af 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -89,6 +89,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; @@ -3018,13 +3023,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); } } @@ -3102,12 +3117,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, @@ -3830,3 +3865,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 27fb23d..ed08841 100644 --- a/common/options.c +++ b/common/options.c @@ -3909,7 +3909,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 ++++++ dhcp-4.1-ESV-R1-xen-checksum.patch ++++++ >From b30af532323bf37e2e953f2ecdcca33c47e90781 Mon Sep 17 00:00:00 2001 From: Marius Tomaschewski <[email protected]> Date: Fri, 18 Feb 2011 13:18:32 +0100 Subject: [PATCH] handle xen partial UDP checksum Applied dhcp-4.2.0-xen-checksum.patch by David Cantrell to handle xen partial UDP checksums (bnc#668194). Signed-off-by: Marius Tomaschewski <[email protected]> --- common/bpf.c | 2 +- common/dlpi.c | 2 +- common/lpf.c | 81 ++++++++++++++++++++++++++++++++++++++++++------------ common/nit.c | 2 +- common/packet.c | 4 +- common/upf.c | 2 +- includes/dhcpd.h | 2 +- 7 files changed, 70 insertions(+), 25 deletions(-) diff --git a/common/bpf.c b/common/bpf.c index a9681bb..9cfeeb1 100644 --- a/common/bpf.c +++ b/common/bpf.c @@ -482,7 +482,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) offset = decode_udp_ip_header (interface, interface -> rbuf, interface -> rbuf_offset, - from, hdr.bh_caplen, &paylen); + from, hdr.bh_caplen, &paylen, 0); /* If the IP or UDP checksum was bad, skip the packet... */ if (offset < 0) { diff --git a/common/dlpi.c b/common/dlpi.c index 3fcf238..4cd40b0 100644 --- a/common/dlpi.c +++ b/common/dlpi.c @@ -692,7 +692,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) length -= offset; #endif offset = decode_udp_ip_header (interface, dbuf, bufix, - from, length, &paylen); + from, length, &paylen, 0); /* * If the IP or UDP checksum was bad, skip the packet... diff --git a/common/lpf.c b/common/lpf.c index e5dd1e2..29111ac 100644 --- a/common/lpf.c +++ b/common/lpf.c @@ -29,18 +29,33 @@ #include "dhcpd.h" #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE) #include <sys/ioctl.h> +#include <sys/socket.h> #include <sys/uio.h> #include <errno.h> #include <asm/types.h> #include <linux/filter.h> #include <linux/if_ether.h> +#include <linux/if_packet.h> #include <netinet/in_systm.h> #include "includes/netinet/ip.h" #include "includes/netinet/udp.h" #include "includes/netinet/if_ether.h" #include <net/if.h> +#ifndef PACKET_AUXDATA +#define PACKET_AUXDATA 8 + +struct tpacket_auxdata +{ + __u32 tp_status; + __u32 tp_len; + __u32 tp_snaplen; + __u16 tp_mac; + __u16 tp_net; +}; +#endif + /* Reinitializes the specified interface after an address change. This is not required for packet-filter APIs. */ @@ -66,10 +81,14 @@ int if_register_lpf (info) struct interface_info *info; { int sock; - struct sockaddr sa; + union { + struct sockaddr_ll ll; + struct sockaddr common; + } sa; + struct ifreq ifr; /* Make an LPF socket. */ - if ((sock = socket(PF_PACKET, SOCK_PACKET, + if ((sock = socket(PF_PACKET, SOCK_RAW, htons((short)ETH_P_ALL))) < 0) { if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || @@ -84,11 +103,16 @@ int if_register_lpf (info) log_fatal ("Open a socket for LPF: %m"); } + memset (&ifr, 0, sizeof ifr); + strncpy (ifr.ifr_name, (const char *)info -> ifp, sizeof ifr.ifr_name); + if (ioctl (sock, SIOCGIFINDEX, &ifr)) + log_fatal ("Failed to get interface index: %m"); + /* Bind to the interface name */ memset (&sa, 0, sizeof sa); - sa.sa_family = AF_PACKET; - strncpy (sa.sa_data, (const char *)info -> ifp, sizeof sa.sa_data); - if (bind (sock, &sa, sizeof sa)) { + sa.ll.sll_family = AF_PACKET; + sa.ll.sll_ifindex = ifr.ifr_ifindex; + if (bind (sock, &sa.common, sizeof sa)) { if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || errno == EAFNOSUPPORT || errno == EINVAL) { @@ -170,9 +194,18 @@ static void lpf_gen_filter_setup (struct interface_info *); void if_register_receive (info) struct interface_info *info; { + int val; + /* Open a LPF device and hang it on this interface... */ info -> rfdesc = if_register_lpf (info); + val = 1; + if (setsockopt (info -> rfdesc, SOL_PACKET, PACKET_AUXDATA, &val, + sizeof val) < 0) { + if (errno != ENOPROTOOPT) + log_fatal ("Failed to set auxiliary packet data: %m"); + } + #if defined (HAVE_TR_SUPPORT) if (info -> hw_address.hbuf [0] == HTYPE_IEEE802) lpf_tr_filter_setup (info); @@ -294,7 +327,6 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) double hh [16]; double ih [1536 / sizeof (double)]; unsigned char *buf = (unsigned char *)ih; - struct sockaddr sa; int result; int fudge; @@ -312,15 +344,7 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) (unsigned char *)raw, len); memcpy (buf + ibufp, raw, len); - /* For some reason, SOCK_PACKET sockets can't be connected, - so we have to do a sentdo every time. */ - memset (&sa, 0, sizeof sa); - sa.sa_family = AF_PACKET; - strncpy (sa.sa_data, - (const char *)interface -> ifp, sizeof sa.sa_data); - - result = sendto (interface -> wfdesc, - buf + fudge, ibufp + len - fudge, 0, &sa, sizeof sa); + result = write (interface -> wfdesc, buf + fudge, ibufp + len - fudge); if (result < 0) log_error ("send_packet: %m"); return result; @@ -337,14 +361,35 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) { int length = 0; int offset = 0; + int nocsum = 0; unsigned char ibuf [1536]; unsigned bufix = 0; unsigned paylen; - - length = read (interface -> rfdesc, ibuf, sizeof ibuf); + unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; + struct iovec iov = { + .iov_base = ibuf, + .iov_len = sizeof ibuf, + }; + struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = cmsgbuf, + .msg_controllen = sizeof(cmsgbuf), + }; + struct cmsghdr *cmsg; + + length = recvmsg (interface -> rfdesc, &msg, 0); if (length <= 0) return length; + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_PACKET && + cmsg->cmsg_type == PACKET_AUXDATA) { + struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg); + nocsum = aux->tp_status & TP_STATUS_CSUMNOTREADY; + } + } + bufix = 0; /* Decode the physical header... */ offset = decode_hw_header (interface, ibuf, bufix, hfrom); @@ -361,7 +406,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) /* Decode the IP and UDP headers... */ offset = decode_udp_ip_header (interface, ibuf, bufix, from, - (unsigned)length, &paylen); + (unsigned)length, &paylen, nocsum); /* If the IP or UDP checksum was bad, skip the packet... */ if (offset < 0) diff --git a/common/nit.c b/common/nit.c index c67e372..c1743fa 100644 --- a/common/nit.c +++ b/common/nit.c @@ -366,7 +366,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) /* Decode the IP and UDP headers... */ offset = decode_udp_ip_header (interface, ibuf, bufix, - from, length, &paylen); + from, length, &paylen, 0); /* If the IP or UDP checksum was bad, skip the packet... */ if (offset < 0) diff --git a/common/packet.c b/common/packet.c index 42bca69..fd2d975 100644 --- a/common/packet.c +++ b/common/packet.c @@ -211,7 +211,7 @@ ssize_t decode_udp_ip_header(struct interface_info *interface, unsigned char *buf, unsigned bufix, struct sockaddr_in *from, unsigned buflen, - unsigned *rbuflen) + unsigned *rbuflen, int nocsum) { unsigned char *data; struct ip ip; @@ -322,7 +322,7 @@ decode_udp_ip_header(struct interface_info *interface, 8, IPPROTO_UDP + ulen)))); udp_packets_seen++; - if (usum && usum != sum) { + if (!nocsum && usum && usum != sum) { udp_packets_bad_checksum++; if (udp_packets_seen > 4 && (udp_packets_seen / udp_packets_bad_checksum) < 2) { diff --git a/common/upf.c b/common/upf.c index 25f7dbd..b1f0c73 100644 --- a/common/upf.c +++ b/common/upf.c @@ -317,7 +317,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) /* Decode the IP and UDP headers... */ offset = decode_udp_ip_header (interface, ibuf, bufix, - from, length, &paylen); + from, length, &paylen, 0); /* If the IP or UDP checksum was bad, skip the packet... */ if (offset < 0) diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 82a3e45..a05532c 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -2591,7 +2591,7 @@ ssize_t decode_hw_header PROTO ((struct interface_info *, unsigned char *, unsigned, struct hardware *)); ssize_t decode_udp_ip_header PROTO ((struct interface_info *, unsigned char *, unsigned, struct sockaddr_in *, - unsigned, unsigned *)); + unsigned, unsigned *, int)); /* ethernet.c */ void assemble_ethernet_header PROTO ((struct interface_info *, unsigned char *, -- 1.7.3.4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Remember to have fun... -- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
