arrfab / rpms / glibc

Forked from rpms/glibc 5 years ago
Clone

Blame SOURCES/glibc-rh1320596.patch

147e83
commit b66d837bb5398795c6b0f651bd5a5d66091d8577
147e83
Author: Florian Weimer <fweimer@redhat.com>
147e83
Date:   Fri Mar 25 11:49:51 2016 +0100
147e83
147e83
    resolv: Always set *resplen2 out parameter in send_dg [BZ #19791]
147e83
    
147e83
    Since commit 44d20bca52ace85850012b0ead37b360e3ecd96e (Implement
147e83
    second fallback mode for DNS requests), there is a code path which
147e83
    returns early, before *resplen2 is initialized.  This happens if the
147e83
    name server address is immediately recognized as invalid (because of
147e83
    lack of protocol support, or if it is a broadcast address such
147e83
    255.255.255.255, or another invalid address).
147e83
    
147e83
    If this happens and *resplen2 was non-zero (which is the case if a
147e83
    previous query resulted in a failure), __libc_res_nquery would reuse
147e83
    an existing second answer buffer.  This answer has been previously
147e83
    identified as unusable (for example, it could be an NXDOMAIN
147e83
    response).  Due to the presence of a second answer, no name server
147e83
    switching will occur.  The result is a name resolution failure,
147e83
    although a successful resolution would have been possible if name
147e83
    servers have been switched and queries had proceeded along the search
147e83
    path.
147e83
    
147e83
    The above paragraph still simplifies the situation.  Before glibc
147e83
    2.23, if the second answer needed malloc, the stub resolver would
147e83
    still attempt to reuse the second answer, but this is not possible
147e83
    because __libc_res_nsearch has freed it, after the unsuccessful call
147e83
    to __libc_res_nquerydomain, and set the buffer pointer to NULL.  This
147e83
    eventually leads to an assertion failure in __libc_res_nquery:
147e83
    
147e83
        /* Make sure both hp and hp2 are defined */
147e83
        assert((hp != NULL) && (hp2 != NULL));
147e83
    
147e83
    If assertions are disabled, the consequence is a NULL pointer
147e83
    dereference on the next line.
147e83
    
147e83
    Starting with glibc 2.23, as a result of commit
147e83
    e9db92d3acfe1822d56d11abcea5bfc4c41cf6ca (CVE-2015-7547: getaddrinfo()
147e83
    stack-based buffer overflow (Bug 18665)), the second answer is always
147e83
    allocated with malloc.  This means that the assertion failure happens
147e83
    with small responses as well because there is no buffer to reuse, as
147e83
    soon as there is a name resolution failure which triggers a search for
147e83
    an answer along the search path.
147e83
    
147e83
    This commit addresses the issue by ensuring that *resplen2 is
147e83
    initialized before the send_dg function returns.
147e83
    
147e83
    This commit also addresses a bug where an invalid second reply is
147e83
    incorrectly returned as a valid to the caller.
147e83
147e83
Index: glibc-2.17-c758a686/resolv/res_send.c
147e83
===================================================================
147e83
--- glibc-2.17-c758a686.orig/resolv/res_send.c
147e83
+++ glibc-2.17-c758a686/resolv/res_send.c
147e83
@@ -672,6 +672,18 @@ libresolv_hidden_def (res_nsend)
147e83
 
147e83
 /* Private */
147e83
 
147e83
+/* Close the resolver structure, assign zero to *RESPLEN2 if RESPLEN2
147e83
+   is not NULL, and return zero.  */
147e83
+static int
147e83
+__attribute__ ((warn_unused_result))
147e83
+close_and_return_error (res_state statp, int *resplen2)
147e83
+{
147e83
+  __res_iclose(statp, false);
147e83
+  if (resplen2 != NULL)
147e83
+    *resplen2 = 0;
147e83
+  return 0;
147e83
+}
147e83
+
147e83
 /* The send_vc function is responsible for sending a DNS query over TCP
147e83
    to the nameserver numbered NS from the res_state STATP i.e.
147e83
    EXT(statp).nssocks[ns].  The function supports sending both IPv4 and
147e83
@@ -1159,7 +1171,11 @@ send_dg(res_state statp,
147e83
  retry_reopen:
147e83
 	retval = reopen (statp, terrno, ns);
147e83
 	if (retval <= 0)
147e83
-		return retval;
147e83
+	  {
147e83
+	    if (resplen2 != NULL)
147e83
+	      *resplen2 = 0;
147e83
+	    return retval;
147e83
+	  }
147e83
  retry:
147e83
 	evNowTime(&now;;
147e83
 	evConsTime(&timeout, seconds, 0);
147e83
@@ -1172,8 +1188,6 @@ send_dg(res_state statp,
147e83
 	int recvresp2 = buf2 == NULL;
147e83
 	pfd[0].fd = EXT(statp).nssocks[ns];
147e83
 	pfd[0].events = POLLOUT;
147e83
-	if (resplen2 != NULL)
147e83
-	  *resplen2 = 0;
147e83
  wait:
147e83
 	if (need_recompute) {
147e83
 	recompute_resend:
147e83
@@ -1181,9 +1195,7 @@ send_dg(res_state statp,
147e83
 		if (evCmpTime(finish, now) <= 0) {
147e83
 		poll_err_out:
147e83
 			Perror(statp, stderr, "poll", errno);
147e83
-		err_out:
147e83
-			__res_iclose(statp, false);
147e83
-			return (0);
147e83
+			return close_and_return_error (statp, resplen2);
147e83
 		}
147e83
 		evSubTime(&timeout, &finish, &now;;
147e83
 		need_recompute = 0;
147e83
@@ -1230,7 +1242,9 @@ send_dg(res_state statp,
147e83
 		  }
147e83
 
147e83
 		*gotsomewhere = 1;
147e83
-		return (0);
147e83
+		if (resplen2 != NULL)
147e83
+		  *resplen2 = 0;
147e83
+		return 0;
147e83
 	}
147e83
 	if (n < 0) {
147e83
 		if (errno == EINTR)
147e83
@@ -1298,7 +1312,7 @@ send_dg(res_state statp,
147e83
 
147e83
 		      fail_sendmmsg:
147e83
 			Perror(statp, stderr, "sendmmsg", errno);
147e83
-			goto err_out;
147e83
+			return close_and_return_error (statp, resplen2);
147e83
 		      }
147e83
 		  }
147e83
 		else
147e83
@@ -1316,7 +1330,7 @@ send_dg(res_state statp,
147e83
 		      if (errno == EINTR || errno == EAGAIN)
147e83
 			goto recompute_resend;
147e83
 		      Perror(statp, stderr, "send", errno);
147e83
-		      goto err_out;
147e83
+		      return close_and_return_error (statp, resplen2);
147e83
 		    }
147e83
 		  just_one:
147e83
 		    if (nwritten != 0 || buf2 == NULL || single_request)
147e83
@@ -1392,7 +1406,7 @@ send_dg(res_state statp,
147e83
 				goto wait;
147e83
 			}
147e83
 			Perror(statp, stderr, "recvfrom", errno);
147e83
-			goto err_out;
147e83
+			return close_and_return_error (statp, resplen2);
147e83
 		}
147e83
 		*gotsomewhere = 1;
147e83
 		if (__builtin_expect (*thisresplenp < HFIXEDSZ, 0)) {
147e83
@@ -1403,7 +1417,7 @@ send_dg(res_state statp,
147e83
 			       (stdout, ";; undersized: %d\n",
147e83
 				*thisresplenp));
147e83
 			*terrno = EMSGSIZE;
147e83
-			goto err_out;
147e83
+			return close_and_return_error (statp, resplen2);
147e83
 		}
147e83
 		if ((recvresp1 || hp->id != anhp->id)
147e83
 		    && (recvresp2 || hp2->id != anhp->id)) {
147e83
@@ -1452,7 +1466,7 @@ send_dg(res_state statp,
147e83
 				? *thisanssizp : *thisresplenp);
147e83
 			/* record the error */
147e83
 			statp->_flags |= RES_F_EDNS0ERR;
147e83
-			goto err_out;
147e83
+			return close_and_return_error (statp, resplen2);
147e83
 	}
147e83
 #endif
147e83
 		if (!(statp->options & RES_INSECURE2)
147e83
@@ -1504,10 +1518,10 @@ send_dg(res_state statp,
147e83
 			    goto wait;
147e83
 			  }
147e83
 
147e83
-			__res_iclose(statp, false);
147e83
 			/* don't retry if called from dig */
147e83
 			if (!statp->pfcode)
147e83
-				return (0);
147e83
+			  return close_and_return_error (statp, resplen2);
147e83
+			__res_iclose(statp, false);
147e83
 		}
147e83
 		if (anhp->rcode == NOERROR && anhp->ancount == 0
147e83
 		    && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
147e83
@@ -1529,6 +1543,8 @@ send_dg(res_state statp,
147e83
 			__res_iclose(statp, false);
147e83
 			// XXX if we have received one reply we could
147e83
 			// XXX use it and not repeat it over TCP...
147e83
+			if (resplen2 != NULL)
147e83
+			  *resplen2 = 0;
147e83
 			return (1);
147e83
 		}
147e83
 		/* Mark which reply we received.  */
147e83
@@ -1544,21 +1560,22 @@ send_dg(res_state statp,
147e83
 					__res_iclose (statp, false);
147e83
 					retval = reopen (statp, terrno, ns);
147e83
 					if (retval <= 0)
147e83
-						return retval;
147e83
+					  {
147e83
+					    if (resplen2 != NULL)
147e83
+					      *resplen2 = 0;
147e83
+					    return retval;
147e83
+					  }
147e83
 					pfd[0].fd = EXT(statp).nssocks[ns];
147e83
 				}
147e83
 			}
147e83
 			goto wait;
147e83
 		}
147e83
-		/*
147e83
-		 * All is well, or the error is fatal.  Signal that the
147e83
-		 * next nameserver ought not be tried.
147e83
-		 */
147e83
+		/* All is well.  We have received both responses (if
147e83
+		   two responses were requested).  */
147e83
 		return (resplen);
147e83
-	} else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
147e83
-		/* Something went wrong.  We can stop trying.  */
147e83
-		goto err_out;
147e83
-	}
147e83
+	} else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))
147e83
+	  /* Something went wrong.  We can stop trying.  */
147e83
+	  return close_and_return_error (statp, resplen2);
147e83
 	else {
147e83
 		/* poll should not have returned > 0 in this case.  */
147e83
 		abort ();