Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Evergreen:Maintenance:405
glibc.openSUSE_13.1_Update
glibc-CVE-2015-7547-patch_3of3_res_send.c.diff
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File glibc-CVE-2015-7547-patch_3of3_res_send.c.diff of Package glibc.openSUSE_13.1_Update
diff -rNU 30 ../glibc-2.18-orig/resolv/res_send.c ./resolv/res_send.c --- ../glibc-2.18-orig/resolv/res_send.c 2016-02-17 19:02:50.000000000 +0100 +++ ./resolv/res_send.c 2016-02-17 19:25:30.000000000 +0100 @@ -634,65 +634,70 @@ if (!v_circuit) { if (!gotsomewhere) __set_errno (ECONNREFUSED); /* no nameservers found */ else __set_errno (ETIMEDOUT); /* no answer obtained */ } else __set_errno (terrno); return (-1); } int res_nsend(res_state statp, const u_char *buf, int buflen, u_char *ans, int anssiz) { return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz, NULL, NULL, NULL, NULL); } libresolv_hidden_def (res_nsend) /* Private */ static int send_vc(res_state statp, const u_char *buf, int buflen, const u_char *buf2, int buflen2, u_char **ansp, int *anssizp, int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2, int *resplen2) { const HEADER *hp = (HEADER *) buf; const HEADER *hp2 = (HEADER *) buf2; +#if 0 u_char *ans = *ansp; int orig_anssizp = *anssizp; // XXX REMOVE // int anssiz = *anssizp; HEADER *anhp = (HEADER *) ans; +#endif +/* CVE-2015-7547 */ + HEADER *anhp = (HEADER *) *ansp; +/* end CVE-2015-7547 for now... */ struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns]; int truncating, connreset, resplen, n; struct iovec iov[4]; u_short len; u_short len2; u_char *cp; if (resplen2 != NULL) *resplen2 = 0; connreset = 0; same_ns: truncating = 0; /* Are we still talking to whom we want to talk to? */ if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) { struct sockaddr_in6 peer; socklen_t size = sizeof peer; if (getpeername(statp->_vcsock, (struct sockaddr *)&peer, &size) < 0 || !sock_eq(&peer, nsap)) { __res_iclose(statp, false); statp->_flags &= ~RES_F_VC; } } if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) { if (statp->_vcsock >= 0) __res_iclose(statp, false); @@ -755,93 +760,103 @@ if (n <= 0) { *terrno = errno; Perror(statp, stderr, "read failed", errno); __res_iclose(statp, false); /* * A long running process might get its TCP * connection reset if the remote server was * restarted. Requery the server instead of * trying a new one. When there is only one * server, this means that a query might work * instead of failing. We only allow one reset * per query to prevent looping. */ if (*terrno == ECONNRESET && !connreset) { connreset = 1; goto same_ns; } return (0); } int rlen = ntohs (rlen16); int *thisanssizp; u_char **thisansp; int *thisresplenp; if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) { thisanssizp = anssizp; thisansp = anscp ?: ansp; assert (anscp != NULL || ansp2 == NULL); thisresplenp = &resplen; } else { +#if 0 /* CVE-2015-7547 until end of #if 0 */ if (*anssizp != MAXPACKET) { /* No buffer allocated for the first reply. We can try to use the rest of the user-provided buffer. */ #ifdef _STRING_ARCH_unaligned *anssizp2 = orig_anssizp - resplen; *ansp2 = *ansp + resplen; #else int aligned_resplen = ((resplen + __alignof__ (HEADER) - 1) & ~(__alignof__ (HEADER) - 1)); *anssizp2 = orig_anssizp - aligned_resplen; *ansp2 = *ansp + aligned_resplen; #endif } else { /* The first reply did not fit into the user-provided buffer. Maybe the second answer will. */ *anssizp2 = orig_anssizp; *ansp2 = *ansp; } - +#endif thisanssizp = anssizp2; thisansp = ansp2; thisresplenp = resplen2; } anhp = (HEADER *) *thisansp; *thisresplenp = rlen; +#if 0 if (rlen > *thisanssizp) { /* Yes, we test ANSCP here. If we have two buffers both will be allocatable. */ if (__builtin_expect (anscp != NULL, 1)) { +#endif + if (*thisanssizp < rlen) { + /* If the current buffer is not the the static + user-supplied buffer then we can reallocate + it. */ + if (thisansp != NULL && thisansp != ansp) { + /* Always allocate MAXPACKET, callers expect + this specific size. */ u_char *newp = malloc (MAXPACKET); if (newp == NULL) { *terrno = ENOMEM; __res_iclose(statp, false); return (0); } *thisanssizp = MAXPACKET; *thisansp = newp; anhp = (HEADER *) newp; len = rlen; } else { Dprint(statp->options & RES_DEBUG, (stdout, ";; response truncated\n") ); truncating = 1; len = *thisanssizp; } } else len = rlen; if (__builtin_expect (len < HFIXEDSZ, 0)) { /* * Undersized message. */ Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", len)); *terrno = EMSGSIZE; __res_iclose(statp, false); return (0); } @@ -969,62 +984,64 @@ * the absence of a nameserver without timing out. */ if (connect(EXT(statp).nssocks[ns], nsap, slen) < 0) { Aerror(statp, stderr, "connect(dg)", errno, nsap); __res_iclose(statp, false); return (0); } if (__builtin_expect (__have_o_nonblock < 0, 0)) { /* Make socket non-blocking. */ int fl = __fcntl (EXT(statp).nssocks[ns], F_GETFL); if (fl != -1) __fcntl (EXT(statp).nssocks[ns], F_SETFL, fl | O_NONBLOCK); Dprint(statp->options & RES_DEBUG, (stdout, ";; new DG socket\n")) } } return 1; } static int send_dg(res_state statp, const u_char *buf, int buflen, const u_char *buf2, int buflen2, u_char **ansp, int *anssizp, int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp, u_char **ansp2, int *anssizp2, int *resplen2) { const HEADER *hp = (HEADER *) buf; const HEADER *hp2 = (HEADER *) buf2; +#if 0 /* CVE-2015-7547 */ u_char *ans = *ansp; int orig_anssizp = *anssizp; +#endif struct timespec now, timeout, finish; struct pollfd pfd[1]; int ptimeout; struct sockaddr_in6 from; int resplen = 0; int n; /* * Compute time for the total operation. */ int seconds = (statp->retrans << ns); if (ns > 0) seconds /= statp->nscount; if (seconds <= 0) seconds = 1; bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0; bool single_request = (((statp->options & RES_SNGLKUP) != 0) | single_request_reopen); int save_gotsomewhere = *gotsomewhere; int retval; retry_reopen: retval = reopen (statp, terrno, ns); if (retval <= 0) return retval; retry: evNowTime(&now); evConsTime(&timeout, seconds, 0); evAddTime(&finish, &now, &timeout); int need_recompute = 0; @@ -1171,99 +1188,128 @@ if (nwritten != 0) sr = send (pfd[0].fd, buf2, buflen2, MSG_NOSIGNAL); else sr = send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL); if (sr != (nwritten != 0 ? buflen2 : buflen)) { if (errno == EINTR || errno == EAGAIN) goto recompute_resend; Perror(statp, stderr, "send", errno); goto err_out; } just_one: if (nwritten != 0 || buf2 == NULL || single_request) pfd[0].events = POLLIN; else pfd[0].events = POLLIN | POLLOUT; ++nwritten; } goto wait; } else if (pfd[0].revents & POLLIN) { int *thisanssizp; u_char **thisansp; int *thisresplenp; if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) { thisanssizp = anssizp; thisansp = anscp ?: ansp; assert (anscp != NULL || ansp2 == NULL); thisresplenp = &resplen; } else { +#if 0 /* CVE-2015-7547 */ if (*anssizp != MAXPACKET) { /* No buffer allocated for the first reply. We can try to use the rest of the user-provided buffer. */ #ifdef _STRING_ARCH_unaligned *anssizp2 = orig_anssizp - resplen; *ansp2 = *ansp + resplen; #else int aligned_resplen = ((resplen + __alignof__ (HEADER) - 1) & ~(__alignof__ (HEADER) - 1)); *anssizp2 = orig_anssizp - aligned_resplen; *ansp2 = *ansp + aligned_resplen; #endif } else { /* The first reply did not fit into the user-provided buffer. Maybe the second answer will. */ *anssizp2 = orig_anssizp; *ansp2 = *ansp; } - +#endif thisanssizp = anssizp2; thisansp = ansp2; thisresplenp = resplen2; } if (*thisanssizp < MAXPACKET +#if 0 /* CVE-2015-7547 */ /* Yes, we test ANSCP here. If we have two buffers both will be allocatable. */ && anscp +#endif + /* If the current buffer is not the the static + user-supplied buffer then we can reallocate it. + */ + && (thisansp != NULL && thisansp != ansp) + /* too small? */ && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0 || *thisanssizp < *thisresplenp)) { + /* Always allocate MAXPACKET, callers expect + this specific size. */ u_char *newp = malloc (MAXPACKET); if (newp != NULL) { +#if 0 /* CVE-2015-7547 */ *anssizp = MAXPACKET; *thisansp = ans = newp; +#endif + *thisanssizp = MAXPACKET; + *thisansp = newp; } } + /* We could end up with truncation if anscp was NULL + (not allowed to change caller's buffer) and the + response buffer size is too small. This isn't a + reliable way to detect truncation because the ioctl + may be an inaccurate report of the UDP message size. + Therefore we use this only to issue debug output. + To do truncation accurately with UDP we need + MSG_TRUNC which is only available on Linux. We + can abstract out the Linux-specific feature in the + future to detect truncation. */ + if (*thisanssizp < *thisresplenp) { + Dprint(statp->options & RES_DEBUG, + (stdout, ";; response may be truncated (UDP)\n") + ); + } HEADER *anhp = (HEADER *) *thisansp; socklen_t fromlen = sizeof(struct sockaddr_in6); assert (sizeof(from) <= fromlen); *thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp, *thisanssizp, 0, (struct sockaddr *)&from, &fromlen); if (__builtin_expect (*thisresplenp <= 0, 0)) { if (errno == EINTR || errno == EAGAIN) { need_recompute = 1; goto wait; } Perror(statp, stderr, "recvfrom", errno); goto err_out; } *gotsomewhere = 1; if (__builtin_expect (*thisresplenp < HFIXEDSZ, 0)) { /* * Undersized message. */ Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", *thisresplenp)); *terrno = EMSGSIZE; goto err_out; } if ((recvresp1 || hp->id != anhp->id) && (recvresp2 || hp2->id != anhp->id)) { /* * response from old query, ignore it. * XXX - potential security hazard could
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor