resolv: Fix a domain search list check

Message ID 20220113162100.24013-1-ppavlu@suse.cz
State New
Headers show
Series
  • resolv: Fix a domain search list check
Related show

Commit Message

Petr Pavlu Jan. 13, 2022, 4:21 p.m.
From: Petr Pavlu <petr.pavlu@suse.com>


Fix a domain search list check in resolv_conf_matches() which verifies
that a resolv_conf extended state matches a given __res_state. The check
counts a length of entries referenced by the resp->dnsrch array and
tests whether it exceeds the combined storage space for the search list,
but wrongly uses a size of resp->dnsrch instead of resp->defdname.

Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>

---

Notes:
    The following is an artificial example which demonstrates the issue:
    > $ cat test.c

    > #include <arpa/inet.h>

    > #include <netdb.h>

    > #include <netinet/in.h>

    > #include <resolv.h>

    > #include <stdio.h>

    > #include <string.h>

    > #include <sys/socket.h>

    > #include <sys/types.h>

    >

    > int main(int argc, char *argv[])

    > {

    >   if (argc < 2) {

    >     fprintf(stderr, "Usage: %s hostname\n", argv[0]);

    >     return 1;

    >   }

    >   const char *hostname = argv[1];

    >

    >   if (res_init() == -1) {

    >     fprintf(stderr, "res_init() failed\n");

    >     return 1;

    >   }

    >

    >   printf("System search domains:\n");

    >   for (size_t i = 0; i < sizeof(_res.dnsrch) / sizeof(_res.dnsrch[0]); i++)

    >     if (_res.dnsrch[i] != NULL)

    >       printf("  %zu: %s\n", i, _res.dnsrch[i]);

    >

    >   printf("Custom search domains:\n");

    >   memset(_res.dnsrch, 0, sizeof(_res.dnsrch));

    >   memset(_res.defdname, 0, sizeof(_res.defdname));

    >   _res.dnsrch[0] = _res.defdname;

    >   snprintf(_res.defdname, sizeof(_res.defdname), "%s",

    >     "012345678901234567890123456789012345678901234567890123456789.example.org");

    >   for (size_t i = 0; i < sizeof(_res.dnsrch) / sizeof(_res.dnsrch[0]); i++)

    >     if (_res.dnsrch[i] != NULL)

    >       printf("  %zu: %s\n", i, _res.dnsrch[i]);

    >

    >   struct addrinfo hints, *result;

    >   memset(&hints, 0, sizeof(hints));

    >   hints.ai_family = AF_INET;

    >   hints.ai_socktype = SOCK_STREAM;

    >   int s = getaddrinfo(hostname, NULL, &hints, &result);

    >   if (s != 0) {

    >     fprintf(stderr, "getaddrinfo() failed: %s\n", gai_strerror(s));

    >     return 1;

    >   }

    >

    >   printf("Resolved addresses:\n");

    >   for (struct addrinfo *p = result; p != NULL; p = p->ai_next) {

    >     struct sockaddr_in *h = (struct sockaddr_in *) p->ai_addr;

    >     printf("  %s\n", inet_ntoa(h->sin_addr));

    >   }

    >   freeaddrinfo(result);

    >

    >   return 0;

    > }

    > $ gcc -Wall -pedantic -lresolv test.c

    > $ cat /etc/resolv

    > search 012345678901234567890123456789012345678901234567890123456789.example.org gnu.org

    > [...]

    
    Previous behaviour:
    > $ ./a.out savannah

    > System search domains:

    >   0: 012345678901234567890123456789012345678901234567890123456789.example.org

    >   1: gnu.org

    > Custom search domains:

    >   0: 012345678901234567890123456789012345678901234567890123456789.example.org

    > Resolved addresses:

    >   209.51.188.72

    
    Updated version which recognizes that _res was modified:
    > $ ./a.out savannah

    > System search domains:

    >   0: 012345678901234567890123456789012345678901234567890123456789.example.org

    >   1: gnu.org

    > Custom search domains:

    >   0: 012345678901234567890123456789012345678901234567890123456789.example.org

    > getaddrinfo() failed: Name or service not known


 resolv/resolv_conf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

-- 
2.26.2

Patch

diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
index 6dd552bb47..ef872dbc14 100644
--- a/resolv/resolv_conf.c
+++ b/resolv/resolv_conf.c
@@ -310,7 +310,7 @@  resolv_conf_matches (const struct __res_state *resp,
                exceeds MAXDNSRCH, or if the combined storage space for
                the search list exceeds what can be stored in
                resp->defdname.  */
-            if (i == MAXDNSRCH || search_list_size > sizeof (resp->dnsrch))
+            if (i == MAXDNSRCH || search_list_size > sizeof (resp->defdname))
               break;
             /* Otherwise, a mismatch indicates a match failure.  */
             return false;