Fix heap corruption on Windows exposed by the use-after free fix.
authorTodd C. Miller <Todd.Miller@sudo.ws>
Wed, 21 Feb 2018 03:18:38 +0000 (20:18 -0700)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Wed, 21 Feb 2018 03:18:38 +0000 (20:18 -0700)
reset_address_cache() could call free_known_addresses() on a struct
addrinfo * that was returned by getaddrinfo().  It seems safest to just
make a copy of the addresses returned by getaddrinfo() so we can always
use free_known_addresses() instead of trying to determine whether or
not we need to use freeaddrinfo().

src/address_cache.c

index 381ae78..2fa9baf 100644 (file)
@@ -169,6 +169,27 @@ const sockaddr_t *get_recent_address(address_cache_t *cache) {
                }
 
                cache->aip = cache->ai = str2addrinfo(address, port, SOCK_STREAM);
+
+               if(cache->ai) {
+                       struct addrinfo *ai = NULL;
+
+                       for(; cache->aip; cache->aip = cache->aip->ai_next) {
+                               struct addrinfo *oai = ai;
+
+                               ai = xzalloc(sizeof(*ai));
+                               ai->ai_family = cache->aip->ai_family;
+                               ai->ai_socktype = cache->aip->ai_socktype;
+                               ai->ai_protocol = cache->aip->ai_protocol;
+                               ai->ai_addrlen = cache->aip->ai_addrlen;
+                               ai->ai_addr = xmalloc(ai->ai_addrlen);
+                               memcpy(ai->ai_addr, cache->aip->ai_addr, ai->ai_addrlen);
+                               ai->ai_next = oai;
+                       }
+
+                       freeaddrinfo(cache->ai);
+                       cache->aip = cache->ai = ai;
+               }
+
                free(address);
                free(port);
 
@@ -182,7 +203,7 @@ const sockaddr_t *get_recent_address(address_cache_t *cache) {
                        cache->aip = cache->aip->ai_next;
                        return sa;
                } else {
-                       freeaddrinfo(cache->ai);
+                       free_known_addresses(cache->ai);
                        cache->ai = NULL;
                }
        }
@@ -234,11 +255,7 @@ void reset_address_cache(address_cache_t *cache, const sockaddr_t *sa) {
        }
 
        if(cache->ai) {
-               if(cache->tried == cache->data.used) {
-                       free_known_addresses(cache->ai);
-               } else {
-                       freeaddrinfo(cache->ai);
-               }
+               free_known_addresses(cache->ai);
        }
 
        cache->config_tree = NULL;
@@ -254,11 +271,7 @@ void close_address_cache(address_cache_t *cache) {
        }
 
        if(cache->ai) {
-               if(cache->tried == cache->data.used) {
-                       free_known_addresses(cache->ai);
-               } else {
-                       freeaddrinfo(cache->ai);
-               }
+               free_known_addresses(cache->ai);
        }
 
        free(cache);