The bind_lease() function has several strdup() calls for the domainname
and nameservers variables, but their return values are not checked.

In my tests, dhclient won't crash even if these strdup() calls return
NULL; however, if one of those variables become NULL as a result, the
"search" or "nameserver" line will be missing in /etc/resolv.conf.  If
both variables are NULL, /etc/resolv.conf won't be updated at all.  In
either case, the user won't know why this happened.

This diff makes the following changes to address this:

- In new_resolv_conf(), confirm that nameservers is not NULL and
  actually has a value before attempting to use it.  While not strictly
  necessary, this makes the code consistent with the domainname check
  right above it.

- In bind_lease(), error out if the strdup() calls fail.  Also
  initialize domainname and nameservers to NULL at the beginning of
  the function; since new_resolv_conf() ensures that these variables
  are not NULL before using them, initializing them to NULL helps us
  avoid the need to do strdup("").

I have tested this diff for almost a week and also with (U)pgrade.

Comments? OK?

Lawrence


Index: dhclient.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhclient.c,v
retrieving revision 1.202
diff -u -p -r1.202 dhclient.c
--- dhclient.c  6 Jan 2013 15:33:12 -0000       1.202
+++ dhclient.c  12 Jan 2013 20:02:13 -0000
@@ -701,7 +701,7 @@ bind_lease(void)
        struct in_addr gateway, mask;
        struct option_data *options;
        struct client_lease *lease;
-       char *domainname, *nameservers;
+       char *domainname = NULL, *nameservers = NULL;
 
        delete_addresses(ifi->name, ifi->rdomain);
        flush_routes_and_arp_cache(ifi->rdomain);
@@ -713,17 +713,19 @@ bind_lease(void)
        memcpy(&mask.s_addr, options[DHO_SUBNET_MASK].data,
            options[DHO_SUBNET_MASK].len);
 
-       if (options[DHO_DOMAIN_NAME].len)
+       if (options[DHO_DOMAIN_NAME].len) {
                domainname = strdup(pretty_print_option(
                    DHO_DOMAIN_NAME, &options[DHO_DOMAIN_NAME], 0));
-       else
-               domainname = strdup("");
+               if (domainname == NULL)
+                       error("no memory for domainname");
+       }
        if (options[DHO_DOMAIN_NAME_SERVERS].len) {
                nameservers = strdup(pretty_print_option(
                    DHO_DOMAIN_NAME_SERVERS,
                    &options[DHO_DOMAIN_NAME_SERVERS], 0));
-       } else
-               nameservers = strdup("");
+               if (nameservers == NULL)
+                       error("no memory for nameservers");
+       }
 
        new_resolv_conf(ifi->name, domainname, nameservers);
 
@@ -1929,13 +1931,15 @@ new_resolv_conf(char *ifname, char *doma
                strlcat(imsg.contents, "\n", MAXRESOLVCONFSIZE);
        }
 
-       for (p = strsep(&nameservers, " "); p != NULL;
-           p = strsep(&nameservers, " ")) {
-               if (*p == '\0')
-                       continue;
-               strlcat(imsg.contents, "nameserver ", MAXRESOLVCONFSIZE);
-               strlcat(imsg.contents, p, MAXRESOLVCONFSIZE);
-               strlcat(imsg.contents, "\n", MAXRESOLVCONFSIZE);
+       if (nameservers && strlen(nameservers)) {
+               for (p = strsep(&nameservers, " "); p != NULL;
+                   p = strsep(&nameservers, " ")) {
+                       if (*p == '\0')
+                               continue;
+                       strlcat(imsg.contents, "nameserver ", 
MAXRESOLVCONFSIZE);
+                       strlcat(imsg.contents, p, MAXRESOLVCONFSIZE);
+                       strlcat(imsg.contents, "\n", MAXRESOLVCONFSIZE);
+               }
        }
 
        rslt = imsg_compose(unpriv_ibuf, IMSG_NEW_RESOLV_CONF, 0, 0, -1, &imsg,

Reply via email to