There are a number of calloc() and strdup() calls in the
apply_defaults() and clone_lease() functions whose return values are not
checked.  If they happen to return NULL, dhclient will segfault.

This diff checks their return values and does some cleanup if they
return NULL.  The diff also ensures that dhclient will not attempt to
make any changes (e.g. delete addresses or flush routes) if it
encounters these errors, but instead will try again at the next retry
interval.

Thoughts/OK?

Lawrence


Index: dhclient.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhclient.c,v
retrieving revision 1.191
diff -u -p -r1.191 dhclient.c
--- dhclient.c  9 Dec 2012 20:28:03 -0000       1.191
+++ dhclient.c  10 Dec 2012 04:09:12 -0000
@@ -677,10 +677,17 @@ bind_lease(void)
        struct client_lease *lease;
        char *domainname, *nameservers;
 
+       lease = apply_defaults(client->new);
+       if (lease == NULL) {
+               client->state = S_INIT;
+               set_timeout_interval(config->retry_interval, state_init);
+               go_daemon();
+               return;
+       }
+
        delete_addresses(ifi->name, ifi->rdomain);
        flush_routes_and_arp_cache(ifi->rdomain);
 
-       lease = apply_defaults(client->new);
        options = lease->options;
 
        memset(&mask, 0, sizeof(mask));
@@ -1939,6 +1946,10 @@ apply_defaults(struct client_lease *leas
        int i, j;
 
        newlease = clone_lease(lease);
+       if (newlease == NULL) {
+               warning("Unable to clone lease");
+               return (NULL);
+       }
 
        for (i = 0; i < 256; i++) {
                for (j = 0; j < config->ignored_option_count; j++) {
@@ -1959,6 +1970,8 @@ apply_defaults(struct client_lease *leas
                        newlease->options[i].len = config->defaults[i].len;
                        newlease->options[i].data = calloc(1, 
                            config->defaults[i].len);
+                       if (newlease->options[i].data == NULL)
+                               goto cleanup;
                        memcpy(newlease->options[i].data,
                            config->defaults[i].data, config->defaults[i].len);
                        break;
@@ -1970,6 +1983,8 @@ apply_defaults(struct client_lease *leas
                            lease->options[i].len;
                        newlease->options[i].data = calloc(1,
                            newlease->options[i].len);
+                       if (newlease->options[i].data == NULL)
+                               goto cleanup;
                        memcpy(newlease->options[i].data,
                            config->defaults[i].data, config->defaults[i].len);
                        memcpy(newlease->options[i].data + 
@@ -1984,6 +1999,8 @@ apply_defaults(struct client_lease *leas
                            lease->options[i].len;
                        newlease->options[i].data = calloc(1,
                            newlease->options[i].len);
+                       if (newlease->options[i].data == NULL)
+                               goto cleanup;
                        memcpy(newlease->options[i].data,
                            lease->options[i].data, lease->options[i].len);
                        memcpy(newlease->options[i].data + 
@@ -1998,6 +2015,8 @@ apply_defaults(struct client_lease *leas
                                    config->defaults[i].len;
                                newlease->options[i].data = calloc(1, 
                                    config->defaults[i].len);
+                               if (newlease->options[i].data == NULL)
+                                       goto cleanup;
                                memcpy(newlease->options[i].data,
                                    config->defaults[i].data,
                                    config->defaults[i].len);
@@ -2010,6 +2029,14 @@ apply_defaults(struct client_lease *leas
        }
 
        return (newlease);
+
+cleanup:
+       if (newlease)
+               free_client_lease(newlease);
+
+       warning("Unable to apply defaults");
+
+       return (NULL);
 }
 
 struct client_lease *
@@ -2019,6 +2046,8 @@ clone_lease(struct client_lease *oldleas
        int i;
 
        newlease = calloc(1, sizeof(struct client_lease));
+       if (newlease == NULL)
+               goto cleanup;
 
        newlease->expiry = oldlease->expiry;
        newlease->renewal = oldlease->renewal;
@@ -2026,19 +2055,33 @@ clone_lease(struct client_lease *oldleas
        newlease->is_static = oldlease->is_static;
        newlease->is_bootp = oldlease->is_bootp;
 
-       if (oldlease->server_name)
+       if (oldlease->server_name) {
                newlease->server_name = strdup(oldlease->server_name);
-       if (oldlease->filename)
+               if (newlease->server_name == NULL)
+                       goto cleanup;
+       }
+       if (oldlease->filename) {
                newlease->filename = strdup(oldlease->filename);
+               if (newlease->filename == NULL)
+                       goto cleanup;
+       }
 
        for (i = 0; i < 256; i++) {
                newlease->options[i].len = oldlease->options[i].len;
                newlease->options[i].data = calloc(1, newlease->options[i].len);
+               if (newlease->options[i].data == NULL)
+                       goto cleanup;
                memcpy(newlease->options[i].data, oldlease->options[i].data,
                    newlease->options[i].len);
        }
 
        return (newlease);
+
+cleanup:
+       if (newlease)
+               free_client_lease(newlease);
+
+       return (NULL);
 }
 
 void

Reply via email to