]> granicus.if.org Git - sudo/commitdiff
Use non-exiting allocators in the redblack tree and fix the fallout.
authorTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 27 May 2015 15:51:54 +0000 (09:51 -0600)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 27 May 2015 15:51:54 +0000 (09:51 -0600)
Also switch to non-exiting allocators in affected code blocks.

12 files changed:
plugins/sudoers/alias.c
plugins/sudoers/gram.c
plugins/sudoers/gram.y
plugins/sudoers/iolog.c
plugins/sudoers/parse.h
plugins/sudoers/pwutil.c
plugins/sudoers/redblack.c
plugins/sudoers/redblack.h
plugins/sudoers/sudoers.c
plugins/sudoers/sudoers.h
plugins/sudoers/testsudoers.c
plugins/sudoers/visudo.c

index f68aa054061847b80fdb8054afa42c6d381cd04b..138dfb6328b482bafc296ba2ccb07e26f2e1c4c7 100644 (file)
@@ -132,10 +132,15 @@ alias_add(char *name, int type, struct member *members)
     a->type = type;
     /* a->used = false; */
     HLTQ_TO_TAILQ(&a->members, members, entries);
-    if (rbinsert(aliases, a)) {
+    switch (rbinsert(aliases, a, NULL)) {
+    case 1:
        snprintf(errbuf, sizeof(errbuf), N_("Alias `%s' already defined"), name);
        alias_free(a);
        debug_return_str(errbuf);
+    case -1:
+       strlcpy(errbuf, N_("unable to allocate memory"), sizeof(errbuf));
+       alias_free(a);
+       debug_return_str(errbuf);
     }
     debug_return_str(NULL);
 }
@@ -209,7 +214,7 @@ alias_remove(char *name, int type)
     debug_return_ptr(rbdelete(aliases, node));
 }
 
-void
+bool
 init_aliases(void)
 {
     debug_decl(init_aliases, SUDOERS_DEBUG_ALIAS)
@@ -218,5 +223,5 @@ init_aliases(void)
        rbdestroy(aliases, alias_free);
     aliases = rbcreate(alias_compare);
 
-    debug_return;
+    debug_return_bool(aliases != NULL);
 }
index 33e01e1fd5be1e127788566e22a8d286bd72b31b..c6ace4ca2bce3241a0c4ed2b9d73afbaba41838b 100644 (file)
@@ -844,12 +844,13 @@ add_userspec(struct member *members, struct privilege *privs)
  * Free up space used by data structures from a previous parser run and sets
  * the current sudoers file to path.
  */
-void
+bool
 init_parser(const char *path, bool quiet)
 {
     struct member_list *binding;
     struct defaults *d, *d_next;
     struct userspec *us, *us_next;
+    bool rval = true;
     debug_decl(init_parser, SUDOERS_DEBUG_PARSER)
 
     TAILQ_FOREACH_SAFE(us, &userspecs, entries, us_next) {
@@ -954,21 +955,31 @@ init_parser(const char *path, bool quiet)
     }
     TAILQ_INIT(&defaults);
 
-    init_aliases();
-
     init_lexer();
 
-    sudo_efree(sudoers);
-    sudoers = path ? sudo_estrdup(path) : NULL;
+    if (!init_aliases()) {
+       sudo_warnx(U_("unable to allocate memory"));
+       rval = false;
+    }
+
+    free(sudoers);
+    if (path != NULL) {
+       if ((sudoers = strdup(path)) == NULL) {
+           sudo_warnx(U_("unable to allocate memory"));
+           rval = false;
+       }
+    } else {
+       sudoers = NULL;
+    }
 
     parse_error = false;
     errorlineno = -1;
     errorfile = sudoers;
     sudoers_warnings = !quiet;
 
-    debug_return;
+    debug_return_bool(rval);
 }
-#line 919 "gram.c"
+#line 930 "gram.c"
 /* allocate initial stack or double stack size, up to YYMAXDEPTH */
 #if defined(__cplusplus) || defined(__STDC__)
 static int yygrowstack(void)
@@ -1877,7 +1888,7 @@ case 113:
                            yyval.member = new_member(yyvsp[0].string, WORD);
                        }
 break;
-#line 1828 "gram.c"
+#line 1839 "gram.c"
     }
     yyssp -= yym;
     yystate = *yyssp;
index 30029fb16f9521c75723e240d29ab6399d88d6ff..f3260bf8e316b57bdf2c83a51bf9aee9b777fb43 100644 (file)
@@ -818,12 +818,13 @@ add_userspec(struct member *members, struct privilege *privs)
  * Free up space used by data structures from a previous parser run and sets
  * the current sudoers file to path.
  */
-void
+bool
 init_parser(const char *path, bool quiet)
 {
     struct member_list *binding;
     struct defaults *d, *d_next;
     struct userspec *us, *us_next;
+    bool rval = true;
     debug_decl(init_parser, SUDOERS_DEBUG_PARSER)
 
     TAILQ_FOREACH_SAFE(us, &userspecs, entries, us_next) {
@@ -928,17 +929,27 @@ init_parser(const char *path, bool quiet)
     }
     TAILQ_INIT(&defaults);
 
-    init_aliases();
-
     init_lexer();
 
-    sudo_efree(sudoers);
-    sudoers = path ? sudo_estrdup(path) : NULL;
+    if (!init_aliases()) {
+       sudo_warnx(U_("unable to allocate memory"));
+       rval = false;
+    }
+
+    free(sudoers);
+    if (path != NULL) {
+       if ((sudoers = strdup(path)) == NULL) {
+           sudo_warnx(U_("unable to allocate memory"));
+           rval = false;
+       }
+    } else {
+       sudoers = NULL;
+    }
 
     parse_error = false;
     errorlineno = -1;
     errorfile = sudoers;
     sudoers_warnings = !quiet;
 
-    debug_return;
+    debug_return_bool(rval);
 }
index 6aac46da1d3155a4731d15b8abd3af27648db458..380b45ec737a31bba69c46d0316108aadfe4bad5 100644 (file)
@@ -587,8 +587,10 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
 
     bindtextdomain("sudoers", LOCALEDIR);
 
-    sudo_setpwent();
-    sudo_setgrent();
+    if (sudo_setpwent() == -1 || sudo_setgrent() == -1) {
+       sudo_warnx(U_("unable to allocate memory"));
+       debug_return_int(-1);
+    }
 
     /* Initialize the debug subsystem.  */
     for (cur = settings; *cur != NULL; cur++) {
index b2dca49566e5e8b5c773f127cfaa88bc67662f61..e51d2326b832a7210b3edfeb39e94609a66c785d 100644 (file)
@@ -192,10 +192,10 @@ struct alias *alias_remove(char *name, int type);
 void alias_apply(int (*func)(void *, void *), void *cookie);
 void alias_free(void *a);
 void alias_put(struct alias *a);
-void init_aliases(void);
+bool init_aliases(void);
 
 /* gram.c */
-void init_parser(const char *, bool);
+bool init_parser(const char *, bool);
 
 /* match_addr.c */
 bool addr_matches(char *n);
index f05a9a090f759de78620e9f9747c5b79e86055be..394bd63e5273b088d0bc108f2ea43fd00087cec2 100644 (file)
@@ -139,16 +139,29 @@ sudo_getpwuid(uid_t uid)
 #endif
     item = sudo_make_pwitem(uid, NULL);
     if (item == NULL) {
-       item = sudo_ecalloc(1, sizeof(*item));
+       item = calloc(1, sizeof(*item));
+       if (item == NULL) {
+           sudo_warnx(U_("unable to cache uid %u, out of memory"),
+               (unsigned int) uid);
+           debug_return_ptr(NULL);
+       }
        item->refcnt = 1;
        item->k.uid = uid;
        /* item->d.pw = NULL; */
     }
-    if (rbinsert(pwcache_byuid, item) != NULL) {
+    switch (rbinsert(pwcache_byuid, item, NULL)) {
+    case 1:
        /* should not happen */
        sudo_warnx(U_("unable to cache uid %u, already exists"),
            (unsigned int) uid);
        item->refcnt = 0;
+       break;
+    case -1:
+       /* can't cache item, just return it */
+       sudo_warnx(U_("unable to cache uid %u, out of memory"),
+           (unsigned int) uid);
+       item->refcnt = 0;
+       break;
     }
 #ifdef HAVE_SETAUTHDB
     aix_restoreauthdb();
@@ -183,16 +196,27 @@ sudo_getpwnam(const char *name)
     item = sudo_make_pwitem((uid_t)-1, name);
     if (item == NULL) {
        len = strlen(name) + 1;
-       item = sudo_ecalloc(1, sizeof(*item) + len);
+       item = calloc(1, sizeof(*item) + len);
+       if (item == NULL) {
+           sudo_warnx(U_("unable to cache user %s, out of memory"), name);
+           debug_return_ptr(NULL);
+       }
        item->refcnt = 1;
        item->k.name = (char *) item + sizeof(*item);
        memcpy(item->k.name, name, len);
        /* item->d.pw = NULL; */
     }
-    if (rbinsert(pwcache_byname, item) != NULL) {
+    switch (rbinsert(pwcache_byname, item, NULL)) {
+    case 1:
        /* should not happen */
        sudo_warnx(U_("unable to cache user %s, already exists"), name);
        item->refcnt = 0;
+       break;
+    case -1:
+       /* can't cache item, just return it */
+       sudo_warnx(U_("unable to cache user %s, out of memory"), name);
+       item->refcnt = 0;
+       break;
     }
 #ifdef HAVE_SETAUTHDB
     aix_restoreauthdb();
@@ -253,15 +277,16 @@ sudo_mkpwent(const char *user, uid_t uid, gid_t gid, const char *home,
        item->refcnt = 1;
        item->d.pw = pw;
        if (i == 0) {
-           /* Store by uid if it doesn't already exist. */
+           /* Store by uid. */
            item->k.uid = pw->pw_uid;
            pwcache = pwcache_byuid;
        } else {
-           /* Store by name if it doesn't already exist. */
+           /* Store by name. */
            item->k.name = pw->pw_name;
            pwcache = pwcache_byname;
        }
-       if ((node = rbinsert(pwcache, item)) != NULL) {
+       switch (rbinsert(pwcache, item, &node)) {
+       case 1:
            /* Already exists. */
            item = node->data;
            if (item->d.pw == NULL) {
@@ -272,6 +297,12 @@ sudo_mkpwent(const char *user, uid_t uid, gid_t gid, const char *home,
                /* Good entry, discard our fake one. */
                sudo_efree(pwitem);
            }
+           break;
+       case -1:
+           /* can't cache item, just return it */
+           sudo_warnx(U_("unable to cache user %s, out of memory"), user);
+           item->refcnt = 0;
+           break;
        }
     }
     item->refcnt++;
@@ -297,18 +328,21 @@ sudo_fakepwnam(const char *user, gid_t gid)
     debug_return_ptr(sudo_mkpwent(user, uid, gid, NULL, NULL));
 }
 
-void
+int
 sudo_setpwent(void)
 {
     debug_decl(sudo_setpwent, SUDOERS_DEBUG_NSS)
 
-    setpwent();
     if (pwcache_byuid == NULL)
        pwcache_byuid = rbcreate(cmp_pwuid);
     if (pwcache_byname == NULL)
        pwcache_byname = rbcreate(cmp_pwnam);
+    if (pwcache_byuid == NULL || pwcache_byname == NULL)
+       debug_return_int(-1);
 
-    debug_return;
+    setpwent();
+
+    debug_return_int(0);
 }
 
 void
@@ -403,11 +437,19 @@ sudo_getgrgid(gid_t gid)
        item->k.gid = gid;
        /* item->d.gr = NULL; */
     }
-    if (rbinsert(grcache_bygid, item) != NULL) {
+    switch (rbinsert(grcache_bygid, item, NULL)) {
+    case 1:
        /* should not happen */
        sudo_warnx(U_("unable to cache gid %u, already exists"),
            (unsigned int) gid);
        item->refcnt = 0;
+       break;
+    case -1:
+       /* can't cache item, just return it */
+       sudo_warnx(U_("unable to cache gid %u, out of memory"),
+           (unsigned int) gid);
+       item->refcnt = 0;
+       break;
     }
 done:
     item->refcnt++;
@@ -442,10 +484,17 @@ sudo_getgrnam(const char *name)
        memcpy(item->k.name, name, len);
        /* item->d.gr = NULL; */
     }
-    if (rbinsert(grcache_byname, item) != NULL) {
+    switch (rbinsert(grcache_byname, item, NULL)) {
+    case 1:
        /* should not happen */
        sudo_warnx(U_("unable to cache group %s, already exists"), name);
        item->refcnt = 0;
+       break;
+    case -1:
+       /* can't cache item, just return it */
+       sudo_warnx(U_("unable to cache group %s, out of memory"), name);
+       item->refcnt = 0;
+       break;
     }
 done:
     item->refcnt++;
@@ -497,7 +546,8 @@ sudo_fakegrnam(const char *group)
            gritem->cache.k.name = gr->gr_name;
            grcache = grcache_byname;
        }
-       if ((node = rbinsert(grcache, item)) != NULL) {
+       switch (rbinsert(grcache, item, &node)) {
+       case 1:
            /* Already exists. */
            item = node->data;
            if (item->d.gr == NULL) {
@@ -508,6 +558,12 @@ sudo_fakegrnam(const char *group)
                /* Good entry, discard our fake one. */
                sudo_efree(gritem);
            }
+           break;
+       case -1:
+           /* can't cache item, just return it */
+           sudo_warnx(U_("unable to cache group %s, out of memory"), group);
+           item->refcnt = 0;
+           break;
        }
     }
     item->refcnt++;
@@ -542,20 +598,23 @@ sudo_grlist_delref(struct group_list *grlist)
     debug_return;
 }
 
-void
+int
 sudo_setgrent(void)
 {
     debug_decl(sudo_setgrent, SUDOERS_DEBUG_NSS)
 
-    setgrent();
     if (grcache_bygid == NULL)
        grcache_bygid = rbcreate(cmp_grgid);
     if (grcache_byname == NULL)
        grcache_byname = rbcreate(cmp_grnam);
     if (grlist_cache == NULL)
        grlist_cache = rbcreate(cmp_grnam);
+    if (grcache_bygid == NULL || grcache_byname == NULL || grlist_cache == NULL)
+       debug_return_int(-1);
 
-    debug_return;
+    setgrent();
+
+    debug_return_int(0);
 }
 
 void
@@ -616,11 +675,19 @@ sudo_get_grlist(const struct passwd *pw)
        memcpy(item->k.name, pw->pw_name, len);
        /* item->d.grlist = NULL; */
     }
-    if (rbinsert(grlist_cache, item) != NULL) {
+    switch (rbinsert(grlist_cache, item, NULL)) {
+    case 1:
        /* should not happen */
        sudo_warnx(U_("unable to cache group list for %s, already exists"),
            pw->pw_name);
        item->refcnt = 0;
+       break;
+    case -1:
+       /* can't cache item, just return it */
+       sudo_warnx(U_("unable to cache group list for %s, out of memory"),
+           pw->pw_name);
+       item->refcnt = 0;
+       break;
     }
 done:
     item->refcnt++;
@@ -643,10 +710,17 @@ sudo_set_grlist(struct passwd *pw, char * const *groups, char * const *gids)
            sudo_warnx(U_("unable to parse groups for %s"), pw->pw_name);
            debug_return_int(-1);
        }
-       if (rbinsert(grlist_cache, item) != NULL) {
+       switch (rbinsert(grlist_cache, item, NULL)) {
+       case 1:
            sudo_warnx(U_("unable to cache group list for %s, already exists"),
                pw->pw_name);
            sudo_grlist_delref_item(item);
+           break;
+       case -1:
+           sudo_warnx(U_("unable to cache group list for %s, out of memory"),
+               pw->pw_name);
+           sudo_grlist_delref_item(item);
+           debug_return_int(-1);
        }
     }
     debug_return_int(0);
index 28b62a497d3be39061ca661ba1ab9a7073aefef1..789f8015ebe1fc9e675e33e72099213321fef24c 100644 (file)
@@ -82,7 +82,8 @@ static void rbdestroy_int(struct rbtree *, struct rbnode *, void (*)(void *));
 
 /*
  * Create a red black tree struct using the specified compare routine.
- * Allocates and returns the initialized (empty) tree.
+ * Allocates and returns the initialized (empty) tree or NULL if
+ * memory cannot be allocated.
  */
 struct rbtree *
 rbcreate(int (*compar)(const void *, const void*))
@@ -90,24 +91,25 @@ rbcreate(int (*compar)(const void *, const void*))
     struct rbtree *tree;
     debug_decl(rbcreate, SUDOERS_DEBUG_RBTREE)
 
-    tree = sudo_emalloc(sizeof(*tree));
-    tree->compar = compar;
-
-    /*
-     * We use a self-referencing sentinel node called nil to simplify the
-     * code by avoiding the need to check for NULL pointers.
-     */
-    tree->nil.left = tree->nil.right = tree->nil.parent = &tree->nil;
-    tree->nil.color = black;
-    tree->nil.data = NULL;
-
-    /*
-     * Similarly, the fake root node keeps us from having to worry
-     * about splitting the root.
-     */
-    tree->root.left = tree->root.right = tree->root.parent = &tree->nil;
-    tree->root.color = black;
-    tree->root.data = NULL;
+    if ((tree = malloc(sizeof(*tree))) != NULL) {
+       tree->compar = compar;
+
+       /*
+        * We use a self-referencing sentinel node called nil to simplify the
+        * code by avoiding the need to check for NULL pointers.
+        */
+       tree->nil.left = tree->nil.right = tree->nil.parent = &tree->nil;
+       tree->nil.color = black;
+       tree->nil.data = NULL;
+
+       /*
+        * Similarly, the fake root node keeps us from having to worry
+        * about splitting the root.
+        */
+       tree->root.left = tree->root.right = tree->root.parent = &tree->nil;
+       tree->root.color = black;
+       tree->root.data = NULL;
+    }
 
     debug_return_ptr(tree);
 }
@@ -166,11 +168,11 @@ rotate_right(struct rbtree *tree, struct rbnode *node)
 
 /*
  * Insert data pointer into a redblack tree.
- * Returns a NULL pointer on success.  If a node matching "data"
- * already exists, a pointer to the existant node is returned.
+ * Returns a 0 on success, 1 if a node matching "data" already exists
+ * (filling in "existing" if not NULL), or -1 on malloc() failure.
  */
-struct rbnode *
-rbinsert(struct rbtree *tree, void *data)
+int
+rbinsert(struct rbtree *tree, void *data, struct rbnode **existing)
 {
     struct rbnode *node = rbfirst(tree);
     struct rbnode *parent = rbroot(tree);
@@ -180,12 +182,17 @@ rbinsert(struct rbtree *tree, void *data)
     /* Find correct insertion point. */
     while (node != rbnil(tree)) {
        parent = node;
-       if ((res = tree->compar(data, node->data)) == 0)
-           debug_return_ptr(node);
+       if ((res = tree->compar(data, node->data)) == 0) {
+           if (existing != NULL)
+               *existing = node;
+           debug_return_int(1);
+       }
        node = res < 0 ? node->left : node->right;
     }
 
-    node = sudo_emalloc(sizeof(*node));
+    node = malloc(sizeof(*node));
+    if (node == NULL)
+       debug_return_int(-1);
     node->data = data;
     node->left = node->right = rbnil(tree);
     node->parent = parent;
@@ -255,7 +262,7 @@ rbinsert(struct rbtree *tree, void *data)
        }
     }
     rbfirst(tree)->color = black;      /* first node is always black */
-    debug_return_ptr(NULL);
+    debug_return_int(0);
 }
 
 /*
@@ -341,13 +348,13 @@ rbdestroy_int(struct rbtree *tree, struct rbnode *node, void (*destroy)(void *))
        rbdestroy_int(tree, node->right, destroy);
        if (destroy != NULL)
            destroy(node->data);
-       sudo_efree(node);
+       free(node);
     }
     debug_return;
 }
 
 /*
- * Destroy the specified tree, calling the destructor destroy
+ * Destroy the specified tree, calling the destructor "destroy"
  * for each node and then freeing the tree itself.
  */
 void
@@ -355,7 +362,7 @@ rbdestroy(struct rbtree *tree, void (*destroy)(void *))
 {
     debug_decl(rbdestroy, SUDOERS_DEBUG_RBTREE)
     rbdestroy_int(tree, rbfirst(tree), destroy);
-    sudo_efree(tree);
+    free(tree);
     debug_return;
 }
 
index cc2103cb8693ca89a43a5e0b2af99c7761f58ce7..5f5a78ce15d05261895b8275dd1fd14b9b741d2e 100644 (file)
@@ -51,7 +51,7 @@ void *rbdelete(struct rbtree *, struct rbnode *);
 int rbapply_node(struct rbtree *, struct rbnode *,
        int (*)(void *, void *), void *, enum rbtraversal);
 struct rbnode *rbfind(struct rbtree *, void *);
-struct rbnode *rbinsert(struct rbtree *, void *);
+int rbinsert(struct rbtree *, void *, struct rbnode **);
 struct rbtree *rbcreate(int (*)(const void *, const void *));
 void rbdestroy(struct rbtree *, void (*)(void *));
 
index e59075a93a8fe5dc5fb34fefed5efbe12cd48f23..0a6195ef52c4fa7ff17a5092f6532eb477485a0f 100644 (file)
@@ -124,8 +124,10 @@ sudoers_policy_init(void *info, char * const envp[])
 
     bindtextdomain("sudoers", LOCALEDIR);
 
-    sudo_setpwent();
-    sudo_setgrent();
+    if (sudo_setpwent() == -1 || sudo_setgrent() == -1) {
+       sudo_warnx(U_("unable to allocate memory"));
+       debug_return_int(-1);
+    }
 
     /* Register fatal/fatalx callback. */
     sudo_fatal_callback_register(sudoers_cleanup);
index 72e14498e22d858c64d84502ea5485d71cd6d961..de4e87f3f223081b527bfdb0feee40a99ccfc8c7 100644 (file)
@@ -303,8 +303,8 @@ void sudo_grlist_delref(struct group_list *);
 void sudo_pw_addref(struct passwd *);
 void sudo_pw_delref(struct passwd *);
 int  sudo_set_grlist(struct passwd *pw, char * const *groups, char * const *gids);
-void sudo_setgrent(void);
-void sudo_setpwent(void);
+int sudo_setgrent(void);
+int sudo_setpwent(void);
 void sudo_setspent(void);
 
 /* timestr.c */
index 72b2d2b5a01b6f8539dc201159ab7a64a1a0f56c..569b7e3d38f5aa992928baa50bad13108907f6ce 100644 (file)
@@ -193,8 +193,8 @@ main(int argc, char *argv[])
        setgrfile(grfile);
     if (pwfile)
        setpwfile(pwfile);
-    sudo_setpwent();
-    sudo_setgrent();
+    if (sudo_setpwent() == -1 || sudo_setgrent() == -1)
+       sudo_fatalx(U_("unable to allocate memory"));
 
     if (argc < 2) {
        if (!dflag)
index ac651d0c3138e46849cebe2a066117ebfa2d92be..2f65f2c31f396be74c45f18d556173443ddee647 100644 (file)
@@ -222,8 +222,8 @@ main(int argc, char *argv[])
     if (argc - optind != 0)
        usage(1);
 
-    sudo_setpwent();
-    sudo_setgrent();
+    if (sudo_setpwent() == -1 || sudo_setgrent() == -1)
+       sudo_fatalx(U_("unable to allocate memory"));
 
     /* Mock up a fake sudo_user struct. */
     user_cmnd = user_base = "";
@@ -1106,7 +1106,8 @@ alias_remove_recursive(char *name, int type)
                    rval = false;
            }
        }
-       rbinsert(alias_freelist, a);
+       if (rbinsert(alias_freelist, a, NULL) != 0)
+           rval = false;
     }
     debug_return_bool(rval);
 }
@@ -1172,6 +1173,10 @@ check_aliases(bool strict, bool quiet)
     debug_decl(check_aliases, SUDOERS_DEBUG_ALIAS)
 
     alias_freelist = rbcreate(alias_compare);
+    if (alias_freelist == NULL) {
+       sudo_warnx(U_("unable to allocate memory"));
+       debug_return_int(-1);
+    }
 
     /* Forward check. */
     TAILQ_FOREACH(us, &userspecs, entries) {