Print this page
5679 be_sort_list(): Possible null pointer dereference

@@ -24,10 +24,11 @@
  */
 
 /*
  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  * Copyright 2015 Toomas Soome <tsoome@me.com>
+ * Copyright 2015 Gary Mills
  */
 
 #include <assert.h>
 #include <libintl.h>
 #include <libnvpair.h>

@@ -65,11 +66,11 @@
 static int be_get_zone_node_data(be_node_list_t *, char *);
 static int be_get_ds_data(zfs_handle_t *, char *, be_dataset_list_t *,
     be_node_list_t *);
 static int be_get_ss_data(zfs_handle_t *, char *, be_snapshot_list_t *,
     be_node_list_t *);
-static void be_sort_list(be_node_list_t **,
+static int be_sort_list(be_node_list_t **,
     int (*)(const void *, const void *));
 static int be_qsort_compare_BEs_name(const void *, const void *);
 static int be_qsort_compare_BEs_name_rev(const void *, const void *);
 static int be_qsort_compare_BEs_date(const void *, const void *);
 static int be_qsort_compare_BEs_date_rev(const void *, const void *);

@@ -141,24 +142,25 @@
  * Function:    be_sort
  * Description: Sort BE node list
  * Parameters:
  *              pointer to address of list head
  *              sort order type
- * Returns:
- *              nothing
+ * Return:
+ *              BE_SUCCESS - Success
+ *              be_errno_t - Failure
  * Side effect:
  *              node list sorted by name
  * Scope:
  *              Public
  */
-void
+int
 be_sort(be_node_list_t **be_nodes, int order)
 {
         int (*compar)(const void *, const void *) = be_qsort_compare_BEs_date;
 
         if (be_nodes == NULL)
-                return;
+                return (BE_ERR_INVAL);
 
         switch (order) {
         case BE_SORT_UNSPECIFIED:
         case BE_SORT_DATE:
                 compar = be_qsort_compare_BEs_date;

@@ -179,14 +181,14 @@
                 compar = be_qsort_compare_BEs_space_rev;
                 break;
         default:
                 be_print_err(gettext("be_sort: invalid sort order %d\n"),
                     order);
-                return;
+                return (BE_ERR_INVAL);
         }
 
-        be_sort_list(be_nodes, compar);
+        return (be_sort_list(be_nodes, compar));
 }
 
 /* ******************************************************************** */
 /*                      Semi-Private Functions                          */
 /* ******************************************************************** */

@@ -212,10 +214,11 @@
 _be_list(char *be_name, be_node_list_t **be_nodes)
 {
         list_callback_data_t cb = { 0 };
         be_transaction_data_t bt = { 0 };
         int ret = BE_SUCCESS;
+        int sret;
         zpool_handle_t *zphp;
         char *rpool = NULL;
         struct be_defaults be_defaults;
 
         if (be_nodes == NULL)

@@ -275,13 +278,13 @@
 
         *be_nodes = cb.be_nodes_head;
 
         free(cb.be_name);
 
-        be_sort(be_nodes, BE_SORT_DATE);
+        sret = be_sort(be_nodes, BE_SORT_DATE);
 
-        return (ret);
+        return ((ret == BE_SUCCESS) ? sret : ret);
 }
 
 /*
  * Function:    be_free_list
  * Description: Frees up all the data allocated for the list of BEs,

@@ -682,34 +685,44 @@
  * Function:    be_sort_list
  * Description: Sort BE node list
  * Parameters:
  *              pointer to address of list head
  *              compare function
- * Returns:
- *              nothing
+ * Return:
+ *              BE_SUCCESS - Success
+ *              be_errno_t - Failure
  * Side effect:
  *              node list sorted by name
  * Scope:
  *              Private
  */
-static void
+static int
 be_sort_list(be_node_list_t **pstart, int (*compar)(const void *, const void *))
 {
+        int ret = BE_SUCCESS;
         size_t ibe, nbe;
         be_node_list_t *p = NULL;
         be_node_list_t **ptrlist = NULL;
+        be_node_list_t **ptrtmp;
 
-        if (pstart == NULL)
-                return;
+        if (pstart == NULL) /* Nothing to sort */
+                return (BE_SUCCESS);
         /* build array of linked list BE struct pointers */
         for (p = *pstart, nbe = 0; p != NULL; nbe++, p = p->be_next_node) {
-                ptrlist = realloc(ptrlist,
+                ptrtmp = realloc(ptrlist,
                     sizeof (be_node_list_t *) * (nbe + 2));
+                if (ptrtmp == NULL) { /* out of memory */
+                        be_print_err(gettext("be_sort_list: memory "
+                            "allocation failed\n"));
+                        ret = BE_ERR_NOMEM;
+                        goto free;
+                }
+                ptrlist = ptrtmp;
                 ptrlist[nbe] = p;
         }
-        if (nbe == 0)
-                return;
+        if (nbe == 0) /* Nothing to sort */
+                return (BE_SUCCESS);
         /* in-place list quicksort using qsort(3C) */
         if (nbe > 1)    /* no sort if less than 2 BEs */
                 qsort(ptrlist, nbe, sizeof (be_node_list_t *), compar);
 
         ptrlist[nbe] = NULL; /* add linked list terminator */

@@ -725,12 +738,14 @@
                         const size_t nmax = ptrlist[ibe]->be_node_num_snapshots;
                         be_snapshot_list_t ** const slist =
                             malloc(sizeof (be_snapshot_list_t *) * (nmax + 1));
                         be_snapshot_list_t *p;
 
-                        if (slist == NULL)
+                        if (slist == NULL) {
+                                ret = BE_ERR_NOMEM;
                                 continue;
+                        }
                         /* build array of linked list snapshot struct ptrs */
                         for (ns = 0, p = ptrlist[ibe]->be_node_snapshots;
                             ns < nmax && p != NULL;
                             ns++, p = p->be_next_snapshot) {
                                 slist[ns] = p;

@@ -753,12 +768,14 @@
                         const size_t nmax = ptrlist[ibe]->be_node_num_datasets;
                         be_dataset_list_t ** const slist =
                             malloc(sizeof (be_dataset_list_t *) * (nmax + 1));
                         be_dataset_list_t *p;
 
-                        if (slist == NULL)
+                        if (slist == NULL) {
+                                ret = BE_ERR_NOMEM;
                                 continue;
+                        }
                         /* build array of linked list dataset struct ptrs */
                         for (ns = 0, p = ptrlist[ibe]->be_node_datasets;
                             ns < nmax && p != NULL;
                             ns++, p = p->be_next_dataset) {
                                 slist[ns] = p;

@@ -777,10 +794,11 @@
                         free(slist);
                 }
         }
 free:
         free(ptrlist);
+        return (ret);
 }
 
 /*
  * Function:    be_qsort_compare_BEs_date
  * Description: compare BE creation times for qsort(3C)