diff --git a/SOURCES/0001-libndp-validate-the-IPv6-hop-limit.patch b/SOURCES/0001-libndp-validate-the-IPv6-hop-limit.patch new file mode 100644 index 0000000..f08e854 --- /dev/null +++ b/SOURCES/0001-libndp-validate-the-IPv6-hop-limit.patch @@ -0,0 +1,142 @@ +From 5d95122c8730616b61a3febe07000a1909874ac0 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Thu, 21 Apr 2016 19:28:29 +0200 +Subject: [PATCH 1/2] libndp: validate the IPv6 hop limit + +None of the NDP messages should ever come from a non-local network; as +stated in RFC4861's 6.1.1 (RS), 6.1.2 (RA), 7.1.1 (NS), 7.1.2 (NA), +and 8.1. (redirect): + + - The IP Hop Limit field has a value of 255, i.e., the packet + could not possibly have been forwarded by a router. + +This fixes CVE-2016-3698. + +Reported by: Julien BERNARD +Signed-off-by: Lubomir Rintel +--- + libndp/libndp.c | 49 +++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 39 insertions(+), 10 deletions(-) + +diff --git a/libndp/libndp.c b/libndp/libndp.c +index 8b7e609..2b85651 100644 +--- a/libndp/libndp.c ++++ b/libndp/libndp.c +@@ -137,7 +137,7 @@ static void *myzalloc(size_t size) + } + + static int myrecvfrom6(int sockfd, void *buf, size_t *buflen, int flags, +- struct in6_addr *addr, uint32_t *ifindex) ++ struct in6_addr *addr, uint32_t *ifindex, int *hoplimit) + { + struct sockaddr_in6 sin6; + unsigned char cbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; +@@ -168,13 +168,26 @@ static int myrecvfrom6(int sockfd, void *buf, size_t *buflen, int flags, + *ifindex = sin6.sin6_scope_id; + for (cmsghdr = CMSG_FIRSTHDR(&msghdr); cmsghdr; + cmsghdr = CMSG_NXTHDR(&msghdr, cmsghdr)) { +- if (cmsghdr->cmsg_level == IPPROTO_IPV6 && +- cmsghdr->cmsg_type == IPV6_PKTINFO && +- cmsghdr->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { +- struct in6_pktinfo *pktinfo; ++ if (cmsghdr->cmsg_level != IPPROTO_IPV6) ++ continue; ++ ++ switch(cmsghdr->cmsg_type) { ++ case IPV6_PKTINFO: ++ if (cmsghdr->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { ++ struct in6_pktinfo *pktinfo; ++ ++ pktinfo = (struct in6_pktinfo *) CMSG_DATA(cmsghdr); ++ *ifindex = pktinfo->ipi6_ifindex; ++ } ++ break; ++ case IPV6_HOPLIMIT: ++ if (cmsghdr->cmsg_len == CMSG_LEN(sizeof(int))) { ++ int *val; + +- pktinfo = (struct in6_pktinfo *) CMSG_DATA(cmsghdr); +- *ifindex = pktinfo->ipi6_ifindex; ++ val = (int *) CMSG_DATA(cmsghdr); ++ *hoplimit = *val; ++ } ++ break; + } + } + *addr = sin6.sin6_addr; +@@ -249,6 +262,15 @@ static int ndp_sock_open(struct ndp *ndp) + goto close_sock; + } + ++ val = 1; ++ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, ++ &val, sizeof(val)); ++ if (ret == -1) { ++ err(ndp, "Failed to setsockopt IPV6_RECVHOPLIMIT,."); ++ err = -errno; ++ goto close_sock; ++ } ++ + ndp->sock = sock; + return 0; + close_sock: +@@ -291,6 +313,7 @@ struct ndp_msg { + size_t len; + struct in6_addr addrto; + uint32_t ifindex; ++ int hoplimit; + struct icmp6_hdr * icmp6_hdr; + unsigned char * opts_start; /* pointer to buf at the + place where opts start */ +@@ -1697,13 +1720,19 @@ static int ndp_sock_recv(struct ndp *ndp) + + len = ndp_msg_payload_maxlen(msg); + err = myrecvfrom6(ndp->sock, msg->buf, &len, 0, +- &msg->addrto, &msg->ifindex); ++ &msg->addrto, &msg->ifindex, &msg->hoplimit); + if (err) { + err(ndp, "Failed to receive message"); + goto free_msg; + } +- dbg(ndp, "rcvd from: %s, ifindex: %u", +- str_in6_addr(&msg->addrto), msg->ifindex); ++ dbg(ndp, "rcvd from: %s, ifindex: %u, hoplimit: %d", ++ str_in6_addr(&msg->addrto), msg->ifindex, msg->hoplimit); ++ ++ if (msg->hoplimit != 255) { ++ warn(ndp, "ignoring packet with bad hop limit (%d)", msg->hoplimit); ++ err = 0; ++ goto free_msg; ++ } + + if (len < sizeof(*msg->icmp6_hdr)) { + warn(ndp, "rcvd icmp6 packet too short (%luB)", len); +-- +2.5.5 + +From e02903973a87f57fea804162a70888ad64003844 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Fri, 13 May 2016 16:07:59 +0200 +Subject: [PATCH] fixup! libndp: validate the IPv6 hop limit + +Actually allocate space for the hop limit. +--- + libndp/libndp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libndp/libndp.c b/libndp/libndp.c +index f817ad6..b7172fa 100644 +--- a/libndp/libndp.c ++++ b/libndp/libndp.c +@@ -140,7 +140,7 @@ static int myrecvfrom6(int sockfd, void *buf, size_t *buflen, int flags, + struct in6_addr *addr, uint32_t *ifindex, int *hoplimit) + { + struct sockaddr_in6 sin6; +- unsigned char cbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; ++ unsigned char cbuf[2 * CMSG_SPACE(sizeof(struct in6_pktinfo))]; + struct iovec iovec; + struct msghdr msghdr; + struct cmsghdr *cmsghdr; +-- +2.5.5 + diff --git a/SOURCES/0002-libndb-reject-redirect-and-router-advertisements-fro.patch b/SOURCES/0002-libndb-reject-redirect-and-router-advertisements-fro.patch new file mode 100644 index 0000000..c73fb51 --- /dev/null +++ b/SOURCES/0002-libndb-reject-redirect-and-router-advertisements-fro.patch @@ -0,0 +1,72 @@ +From b05d91c33f5d679aa3aab190d52f9cdf3189cffb Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Thu, 21 Apr 2016 19:40:52 +0200 +Subject: [PATCH 2/2] libndb: reject redirect and router advertisements from + non-link-local + +RFC4861 suggests that these messages should only originate from +link-local addresses in 6.1.2 (RA) and 8.1. (redirect): + +Mitigates CVE-2016-3698. + +Signed-off-by: Lubomir Rintel +--- + libndp/libndp.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/libndp/libndp.c b/libndp/libndp.c +index 2b85651..f817ad6 100644 +--- a/libndp/libndp.c ++++ b/libndp/libndp.c +@@ -333,6 +333,7 @@ struct ndp_msg_type_info { + uint8_t raw_type; + size_t raw_struct_size; + void (*addrto_adjust)(struct in6_addr *addr); ++ bool (*addrto_validate)(struct in6_addr *addr); + }; + + static void ndp_msg_addrto_adjust_all_nodes(struct in6_addr *addr) +@@ -359,6 +360,11 @@ static void ndp_msg_addrto_adjust_all_routers(struct in6_addr *addr) + addr->s6_addr32[3] = htonl(0x2); + } + ++static bool ndp_msg_addrto_validate_link_local(struct in6_addr *addr) ++{ ++ return IN6_IS_ADDR_LINKLOCAL (addr); ++} ++ + static struct ndp_msg_type_info ndp_msg_type_info_list[] = + { + [NDP_MSG_RS] = { +@@ -371,6 +377,7 @@ static struct ndp_msg_type_info ndp_msg_type_info_list[] = + .strabbr = "RA", + .raw_type = ND_ROUTER_ADVERT, + .raw_struct_size = sizeof(struct nd_router_advert), ++ .addrto_validate = ndp_msg_addrto_validate_link_local, + }, + [NDP_MSG_NS] = { + .strabbr = "NS", +@@ -387,6 +394,7 @@ static struct ndp_msg_type_info ndp_msg_type_info_list[] = + .strabbr = "R", + .raw_type = ND_REDIRECT, + .raw_struct_size = sizeof(struct nd_redirect), ++ .addrto_validate = ndp_msg_addrto_validate_link_local, + }, + }; + +@@ -418,7 +426,11 @@ static bool ndp_msg_check_valid(struct ndp_msg *msg) + + if (len < ndp_msg_type_info(msg_type)->raw_struct_size) + return false; +- return true; ++ ++ if (ndp_msg_type_info(msg_type)->addrto_validate) ++ return ndp_msg_type_info(msg_type)->addrto_validate(&msg->addrto); ++ else ++ return true; + } + + static struct ndp_msg *ndp_msg_alloc(void) +-- +2.5.5 + diff --git a/SPECS/libndp.spec b/SPECS/libndp.spec index 04defa5..c44baa3 100644 --- a/SPECS/libndp.spec +++ b/SPECS/libndp.spec @@ -1,6 +1,6 @@ Name: libndp Version: 1.2 -Release: 4%{?dist} +Release: 6%{?dist} Summary: Library for Neighbor Discovery Protocol Group: System Environment/Libraries License: LGPLv2+ @@ -8,6 +8,8 @@ URL: http://www.libndp.org/ Source: http://www.libndp.org/files/libndp-%{version}.tar.gz Patch0: 0001-libndp-fix-cppcheck-Undefined-behavior-Variable-buf-.patch +Patch1: 0001-libndp-validate-the-IPv6-hop-limit.patch +Patch2: 0002-libndb-reject-redirect-and-router-advertisements-fro.patch %description This package contains a library which provides a wrapper @@ -26,6 +28,8 @@ necessary for developing programs using libndp. %prep %setup -q %patch0 -p1 -b .fix_cppcheck_var_buf +%patch1 -p1 -b .hop-limit +%patch2 -p1 -b .link-local %build %configure --disable-static @@ -51,6 +55,13 @@ find $RPM_BUILD_ROOT -name \*.la -delete %{_libdir}/pkgconfig/*.pc %changelog +* Sat May 14 2016 Lubomir Rintel - 1.2-6 +- libndp: fix hop limit validation [CVE-2016-3698] + +* Fri May 06 2016 Lubomir Rintel - 1.2-5 +- libndp: validate the IPv6 hop limit [CVE-2016-3698] +- libndb: reject redirect and router advertisements from non-link-local [CVE-2016-3698] + * Fri Jan 24 2014 Daniel Mach - 1.2-4 - Mass rebuild 2014-01-24