resolv: Fix a domain search list check
Checks
Context |
Check |
Description |
dj/TryBot-apply_patch |
success
|
Patch applied to master at the time it was sent
|
dj/TryBot-32bit |
success
|
Build for i686
|
Commit Message
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(-)
@@ -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;