arrfab / rpms / glibc

Forked from rpms/glibc 5 years ago
Clone

Blame SOURCES/glibc-rh1098047.patch

147e83
commit 16b293a7a6f65d8ff348a603d19e8fd4372fa3a9
147e83
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
147e83
Date:   Wed Apr 30 11:48:43 2014 +0530
147e83
147e83
    Do not fail if one of the two responses to AF_UNSPEC fails (BZ #14308)
147e83
    
147e83
    [Fixes BZ #14308, #12994, #13651]
147e83
    
147e83
    AF_UNSPEC results in sending two queries in parallel, one for the A
147e83
    record and the other for the AAAA record.  If one of these is a
147e83
    referral, then the query fails, which is wrong.  It should return at
147e83
    least the one successful response.
147e83
    
147e83
    The fix has two parts.  The first part makes the referral fall back to
147e83
    the SERVFAIL path, which results in using the successful response.
147e83
    There is a bug in that path however, due to which the second part is
147e83
    necessary.  The bug here is that if the first response is a failure
147e83
    and the second succeeds, __libc_res_nsearch does not detect that and
147e83
    assumes a failure.  The case where the first response is a success and
147e83
    the second fails, works correctly.
147e83
    
147e83
    This condition is produced by buggy routers, so here's a crude
147e83
    interposable library that can simulate such a condition.  The library
147e83
    overrides the recvfrom syscall and modifies the header of the packet
147e83
    received to reproduce this scenario.  It has two key variables:
147e83
    mod_packet and first_error.
147e83
    
147e83
    The mod_packet variable when set to 0, results in odd packets being
147e83
    modified to be a referral.  When set to 1, even packets are modified
147e83
    to be a referral.
147e83
    
147e83
    The first_error causes the first response to be a failure so that a
147e83
    domain-appended search is performed to test the second part of the
147e83
    __libc_nsearch fix.
147e83
    
147e83
    The driver for this fix is a simple getaddrinfo program that does an
147e83
    AF_UNSPEC query.  I have omitted this since it should be easy to
147e83
    implement.
147e83
    
147e83
    I have tested this on x86_64.
147e83
    
147e83
    The interceptor library source:
147e83
    
147e83
    /* Override recvfrom and modify the header of the first DNS response to make it
147e83
       a referral and reproduce bz #845218.  We have to resort to this ugly hack
147e83
       because we cannot make bind return the buggy response of a referral for the
147e83
       AAAA record and an authoritative response for the A record.  */
147e83
     #define _GNU_SOURCE
147e83
     #include <sys/types.h>
147e83
     #include <sys/socket.h>
147e83
     #include <netinet/in.h>
147e83
     #include <arpa/inet.h>
147e83
     #include <stdio.h>
147e83
     #include <stdbool.h>
147e83
     #include <endian.h>
147e83
     #include <dlfcn.h>
147e83
     #include <stdlib.h>
147e83
    
147e83
    /* Lifted from resolv/arpa/nameser_compat.h.  */
147e83
    typedef struct {
147e83
        unsigned        id :16;         /*%< query identification number */
147e83
     #if BYTE_ORDER == BIG_ENDIAN
147e83
        /* fields in third byte */
147e83
        unsigned        qr: 1;          /*%< response flag */
147e83
        unsigned        opcode: 4;      /*%< purpose of message */
147e83
        unsigned        aa: 1;          /*%< authoritive answer */
147e83
        unsigned        tc: 1;          /*%< truncated message */
147e83
        unsigned        rd: 1;          /*%< recursion desired */
147e83
        /* fields
147e83
         * in
147e83
         * fourth
147e83
         * byte
147e83
         * */
147e83
        unsigned        ra: 1;          /*%< recursion available */
147e83
        unsigned        unused :1;      /*%< unused bits (MBZ as of 4.9.3a3) */
147e83
        unsigned        ad: 1;          /*%< authentic data from named */
147e83
        unsigned        cd: 1;          /*%< checking disabled by resolver */
147e83
        unsigned        rcode :4;       /*%< response code */
147e83
     #endif
147e83
     #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
147e83
        /* fields
147e83
         * in
147e83
         * third
147e83
         * byte
147e83
         * */
147e83
        unsigned        rd :1;          /*%< recursion desired */
147e83
        unsigned        tc :1;          /*%< truncated message */
147e83
        unsigned        aa :1;          /*%< authoritive answer */
147e83
        unsigned        opcode :4;      /*%< purpose of message */
147e83
        unsigned        qr :1;          /*%< response flag */
147e83
        /* fields
147e83
         * in
147e83
         * fourth
147e83
         * byte
147e83
         * */
147e83
        unsigned        rcode :4;       /*%< response code */
147e83
        unsigned        cd: 1;          /*%< checking disabled by resolver */
147e83
        unsigned        ad: 1;          /*%< authentic data from named */
147e83
        unsigned        unused :1;      /*%< unused bits (MBZ as of 4.9.3a3) */
147e83
        unsigned        ra :1;          /*%< recursion available */
147e83
     #endif
147e83
        /* remaining
147e83
         * bytes
147e83
         * */
147e83
        unsigned        qdcount :16;    /*%< number of question entries */
147e83
        unsigned        ancount :16;    /*%< number of answer entries */
147e83
        unsigned        nscount :16;    /*%< number of authority entries */
147e83
        unsigned        arcount :16;    /*%< number of resource entries */
147e83
    } HEADER;
147e83
    
147e83
    static int done = 0;
147e83
    
147e83
    /* Packets to modify.  0 for the odd packets and 1 for even packets.  */
147e83
    static const int mod_packet = 0;
147e83
    
147e83
    /* Set to true if the first request should result in an error, resulting in a
147e83
       search query.  */
147e83
    static bool first_error = true;
147e83
    
147e83
    static ssize_t (*real_recvfrom) (int sockfd, void *buf, size_t len, int flags,
147e83
    			  struct sockaddr *src_addr, socklen_t *addrlen);
147e83
    
147e83
    void
147e83
    __attribute__ ((constructor))
147e83
    init (void)
147e83
    {
147e83
      real_recvfrom = dlsym (RTLD_NEXT, "recvfrom");
147e83
    
147e83
      if (real_recvfrom == NULL)
147e83
        {
147e83
          printf ("Failed to get reference to recvfrom: %s\n", dlerror ());
147e83
          printf ("Cannot simulate test\n");
147e83
          abort ();
147e83
        }
147e83
    }
147e83
    
147e83
    /* Modify the second packet that we receive to set the header in a manner as to
147e83
       reproduce BZ #845218.  */
147e83
    static void
147e83
    mod_buf (HEADER *h, int port)
147e83
    {
147e83
      if (done % 2 == mod_packet || (first_error && done == 1))
147e83
        {
147e83
          printf ("(Modifying header)");
147e83
    
147e83
          if (first_error && done == 1)
147e83
    	h->rcode = 3;
147e83
          else
147e83
    	h->rcode = 0;	/* NOERROR == 0.  */
147e83
          h->ancount = 0;
147e83
          h->aa = 0;
147e83
          h->ra = 0;
147e83
          h->arcount = 0;
147e83
        }
147e83
      done++;
147e83
    }
147e83
    
147e83
    ssize_t
147e83
    recvfrom (int sockfd, void *buf, size_t len, int flags,
147e83
    	  struct sockaddr *src_addr, socklen_t *addrlen)
147e83
    {
147e83
      ssize_t ret = real_recvfrom (sockfd, buf, len, flags, src_addr, addrlen);
147e83
      int port = htons (((struct sockaddr_in *) src_addr)->sin_port);
147e83
      struct in_addr addr = ((struct sockaddr_in *) src_addr)->sin_addr;
147e83
      const char *host = inet_ntoa (addr);
147e83
      printf ("\n*** From %s:%d: ", host, port);
147e83
    
147e83
      mod_buf (buf, port);
147e83
    
147e83
      printf ("returned %zd\n", ret);
147e83
      return ret;
147e83
    }
147e83
147e83
 ChangeLog          | 11 +++++++++++
147e83
 NEWS               | 14 +++++++-------
147e83
 resolv/res_query.c |  7 +++++--
147e83
 resolv/res_send.c  |  2 +-
147e83
 4 files changed, 24 insertions(+), 10 deletions(-)
147e83
147e83
commit e35c53e397e7abbd41fedacdedcfa5af7b5c2c52
147e83
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
147e83
Date:   Tue Jul 8 16:40:24 2014 +0530
147e83
147e83
    Check value at resplen2 if it is not NULL
147e83
    
147e83
    There was a typo in the previous patch due to which resplen2 was
147e83
    checked for non-zero instead of the value at resplen2.  Fix that and
147e83
    improve the condition by checking resplen2 for non-NULL (instead of
147e83
    answerp2) and also adding the check in a third place.
147e83
147e83
 ChangeLog          | 3 +++
147e83
 resolv/res_query.c | 9 +++++----
147e83
 2 files changed, 8 insertions(+), 4 deletions(-)
147e83
147e83
diff -pruN glibc-2.17-c758a686/resolv/res_query.c glibc-2.17-c758a686/resolv/res_query.c
147e83
--- glibc-2.17-c758a686/resolv/res_query.c	2012-12-25 08:32:13.000000000 +0530
147e83
+++ glibc-2.17-c758a686/resolv/res_query.c	2014-09-05 14:28:06.439191017 +0530
147e83
@@ -378,7 +378,9 @@ __libc_res_nsearch(res_state statp,
147e83
 		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
147e83
 					      answer, anslen, answerp,
147e83
 					      answerp2, nanswerp2, resplen2);
147e83
-		if (ret > 0 || trailing_dot)
147e83
+		if (ret > 0 || trailing_dot
147e83
+		    /* If the second response is valid then we use that.  */
147e83
+		    || (ret == 0 && resplen2 != NULL && *resplen2 > 0))
147e83
 			return (ret);
147e83
 		saved_herrno = h_errno;
147e83
 		tried_as_is++;
147e83
@@ -418,7 +420,8 @@ __libc_res_nsearch(res_state statp,
147e83
 						      answer, anslen, answerp,
147e83
 						      answerp2, nanswerp2,
147e83
 						      resplen2);
147e83
-			if (ret > 0)
147e83
+			if (ret > 0 || (ret == 0 && resplen2 != NULL
147e83
+					&& *resplen2 > 0))
147e83
 				return (ret);
147e83
 
147e83
 			if (answerp && *answerp != answer) {
147e83
@@ -487,7 +490,8 @@ __libc_res_nsearch(res_state statp,
147e83
 		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
147e83
 					      answer, anslen, answerp,
147e83
 					      answerp2, nanswerp2, resplen2);
147e83
-		if (ret > 0)
147e83
+		if (ret > 0 || (ret == 0 && resplen2 != NULL
147e83
+				&& *resplen2 > 0))
147e83
 			return (ret);
147e83
 	}
147e83
 
147e83
diff -pruN glibc-2.17-c758a686/resolv/res_send.c glibc-2.17-c758a686/resolv/res_send.c
147e83
--- glibc-2.17-c758a686/resolv/res_send.c	2014-09-05 14:28:30.039337246 +0530
147e83
+++ glibc-2.17-c758a686/resolv/res_send.c	2014-09-05 14:28:06.439191017 +0530
147e83
@@ -1343,6 +1343,7 @@ send_dg(res_state statp,
147e83
 				(*thisresplenp > *thisanssizp)
147e83
 				? *thisanssizp : *thisresplenp);
147e83
 
147e83
+		next_ns:
147e83
 			if (recvresp1 || (buf2 != NULL && recvresp2)) {
147e83
 			  *resplen2 = 0;
147e83
 			  return resplen;
147e83
@@ -1360,7 +1361,6 @@ send_dg(res_state statp,
147e83
 			    goto wait;
147e83
 			  }
147e83
 
147e83
-		next_ns:
147e83
 			__res_iclose(statp, false);
147e83
 			/* don't retry if called from dig */
147e83
 			if (!statp->pfcode)