[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen stable-4.13] tools/xenstore: use treewalk for check_store()



commit 1cfbd2567b68e3e021a963d6f45f6adfa359c8d4
Author:     Juergen Gross <jgross@xxxxxxxx>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: use treewalk for check_store()
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when checking the store for inconsistencies.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
    Reviewed-by: Julien Grall <jgrall@xxxxxxxxxx>
    (cherry picked from commit a07cc0ec60612f414bedf2bafb26ec38d2602e95)
---
 tools/xenstore/xenstored_core.c | 105 +++++++++++-----------------------------
 1 file changed, 28 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 877e88560c..fb25f72017 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2242,18 +2242,6 @@ int remember_string(struct hashtable *hash, const char 
*str)
        return hashtable_insert(hash, k, (void *)1);
 }
 
-static int rm_child_entry(struct node *node, size_t off, size_t len)
-{
-       if (!recovery)
-               return off;
-
-       if (remove_child_entry(NULL, node, off))
-               log("check_store: child entry could not be removed from '%s'",
-                   node->name);
-
-       return off - len - 1;
-}
-
 /**
  * A node has a children field that names the children of the node, separated
  * by NULs.  We check whether there are entries in there that are duplicated
@@ -2267,70 +2255,29 @@ static int rm_child_entry(struct node *node, size_t 
off, size_t len)
  * As we go, we record each node in the given reachable hashtable.  These
  * entries will be used later in clean_store.
  */
-static int check_store_(const char *name, struct hashtable *reachable)
+static int check_store_step(const void *ctx, struct connection *conn,
+                           struct node *node, void *arg)
 {
-       struct node *node = read_node(NULL, name, name);
-       int ret = 0;
-
-       if (node) {
-               size_t i = 0;
-
-               if (!remember_string(reachable, name)) {
-                       log("check_store: ENOMEM");
-                       return ENOMEM;
-               }
-
-               while (i < node->childlen && !ret) {
-                       struct node *childnode = NULL;
-                       size_t childlen = strlen(node->children + i);
-                       char *childname = child_name(NULL, node->name,
-                                                    node->children + i);
-
-                       if (!childname) {
-                               log("check_store: ENOMEM");
-                               ret = ENOMEM;
-                               break;
-                       }
-
-                       if (hashtable_search(reachable, childname)) {
-                               log("check_store: '%s' is duplicated!",
-                                   childname);
-                               i = rm_child_entry(node, i, childlen);
-                               goto next;
-                       }
+       struct hashtable *reachable = arg;
 
-                       childnode = read_node(NULL, childname, childname);
-
-                       if (childnode) {
-                               ret = check_store_(childname, reachable);
-                       } else if (errno != ENOMEM) {
-                               log("check_store: No child '%s' found!\n",
-                                   childname);
-                               i = rm_child_entry(node, i, childlen);
-                       } else {
-                               log("check_store: ENOMEM");
-                               ret = ENOMEM;
-                       }
+       if (hashtable_search(reachable, (void *)node->name)) {
+               log("check_store: '%s' is duplicated!", node->name);
+               return recovery ? WALK_TREE_RM_CHILDENTRY
+                               : WALK_TREE_SKIP_CHILDREN;
+       }
 
- next:
-                       talloc_free(childnode);
-                       talloc_free(childname);
-                       i += childlen + 1;
-               }
+       if (!remember_string(reachable, node->name))
+               return WALK_TREE_ERROR_STOP;
 
-               talloc_free(node);
-       } else if (errno != ENOMEM) {
-               /* Impossible, because no database should ever be without the
-                  root, and otherwise, we've just checked in our caller
-                  (which made a recursive call to get here). */
+       return WALK_TREE_OK;
+}
 
-               log("check_store: No child '%s' found: impossible!", name);
-       } else {
-               log("check_store: ENOMEM");
-               ret = ENOMEM;
-       }
+static int check_store_enoent(const void *ctx, struct connection *conn,
+                             struct node *parent, char *name, void *arg)
+{
+       log("check_store: node '%s' not found", name);
 
-       return ret;
+       return recovery ? WALK_TREE_RM_CHILDENTRY : WALK_TREE_OK;
 }
 
 
@@ -2379,24 +2326,28 @@ static void clean_store(struct hashtable *reachable)
 
 void check_store(void)
 {
-       char * root = talloc_strdup(NULL, "/");
-       struct hashtable * reachable =
-               create_hashtable(16, hash_from_key_fn, keys_equal_fn);
- 
+       struct hashtable *reachable;
+       struct walk_funcs walkfuncs = {
+               .enter = check_store_step,
+               .enoent = check_store_enoent,
+       };
+
+       reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
        if (!reachable) {
                log("check_store: ENOMEM");
                return;
        }
 
        log("Checking store ...");
-       if (!check_store_(root, reachable) &&
-           !check_transactions(reachable))
+       if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) {
+               if (errno == ENOMEM)
+                       log("check_store: ENOMEM");
+       } else if (!check_transactions(reachable))
                clean_store(reachable);
        log("Checking store complete.");
 
        hashtable_destroy(reachable, 0 /* Don't free values (they are all
                                          (void *)1) */);
-       talloc_free(root);
 }
 
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.