Blob Blame History Raw
commit f1f00c072138af90ae6da180f260111f09afe7a3
Author: Florian Weimer <fweimer@redhat.com>
Date:   Wed Oct 14 10:54:39 2020 +0200

    resolv: Handle transaction ID collisions in parallel queries (bug 26600)
    
    If the transaction IDs are equal, the old check attributed both
    responses to the first query, not recognizing the second response.
    This fixes bug 26600.

[dj: stripped out testsuite parts]

diff --git a/resolv/res_send.c b/resolv/res_send.c
index c9b02cca130bc20d..ac19627634281c2f 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -1315,15 +1315,6 @@ send_dg(res_state statp,
 			*terrno = EMSGSIZE;
 			return close_and_return_error (statp, resplen2);
 		}
-		if ((recvresp1 || hp->id != anhp->id)
-		    && (recvresp2 || hp2->id != anhp->id)) {
-			/*
-			 * response from old query, ignore it.
-			 * XXX - potential security hazard could
-			 *	 be detected here.
-			 */
-			goto wait;
-		}
 
 		/* Paranoia check.  Due to the connected UDP socket,
 		   the kernel has already filtered invalid addresses
@@ -1333,15 +1324,24 @@ send_dg(res_state statp,
 
 		/* Check for the correct header layout and a matching
 		   question.  */
-		if ((recvresp1 || !res_queriesmatch(buf, buf + buflen,
-						       *thisansp,
-						       *thisansp
-						       + *thisanssizp))
-		    && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
-						       *thisansp,
-						       *thisansp
-						       + *thisanssizp)))
-		  goto wait;
+		int matching_query = 0; /* Default to no matching query.  */
+		if (!recvresp1
+		    && anhp->id == hp->id
+		    && res_queriesmatch (buf, buf + buflen,
+					 *thisansp, *thisansp + *thisanssizp))
+		  matching_query = 1;
+		if (!recvresp2
+		    && anhp->id == hp2->id
+		    && res_queriesmatch (buf2, buf2 + buflen2,
+					 *thisansp, *thisansp + *thisanssizp))
+		  matching_query = 2;
+		if (matching_query == 0)
+		  /* Spurious UDP packet.  Drop it and continue
+		     waiting.  */
+		  {
+		    need_recompute = 1;
+		    goto wait;
+		  }
 
 		if (anhp->rcode == SERVFAIL ||
 		    anhp->rcode == NOTIMP ||
@@ -1356,7 +1356,7 @@ send_dg(res_state statp,
 			    /* No data from the first reply.  */
 			    resplen = 0;
 			    /* We are waiting for a possible second reply.  */
-			    if (hp->id == anhp->id)
+			    if (matching_query == 1)
 			      recvresp1 = 1;
 			    else
 			      recvresp2 = 1;
@@ -1387,7 +1387,7 @@ send_dg(res_state statp,
 			return (1);
 		}
 		/* Mark which reply we received.  */
-		if (recvresp1 == 0 && hp->id == anhp->id)
+		if (matching_query == 1)
 			recvresp1 = 1;
 		else
 			recvresp2 = 1;