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

[xen stable-4.15] tools/xenstore: use treewalk for creating node records



commit 84674f206778e9b3d8d67c6c76aa8094a262d5ec
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:03:25 2022 +0000

    tools/xenstore: use treewalk for creating node records
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when creating the node records during a live update.
    
    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 297ac246a5d8ed656b349641288f3402dcc0251e)
---
 tools/xenstore/xenstored_core.c   | 127 ++++++++++++++++----------------------
 tools/xenstore/xenstored_core.h   |   3 +-
 tools/xenstore/xenstored_domain.c |   2 +-
 3 files changed, 54 insertions(+), 78 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 9576411757..e8cdfeef50 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2990,132 +2990,109 @@ const char *dump_state_buffered_data(FILE *fp, const 
struct connection *c,
        return NULL;
 }
 
-const char *dump_state_node_perms(FILE *fp, struct xs_state_node *sn,
-                                 const struct xs_permissions *perms,
+const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms,
                                  unsigned int n_perms)
 {
        unsigned int p;
 
        for (p = 0; p < n_perms; p++) {
+               struct xs_state_node_perm sp;
+
                switch ((int)perms[p].perms & ~XS_PERM_IGNORE) {
                case XS_PERM_READ:
-                       sn->perms[p].access = XS_STATE_NODE_PERM_READ;
+                       sp.access = XS_STATE_NODE_PERM_READ;
                        break;
                case XS_PERM_WRITE:
-                       sn->perms[p].access = XS_STATE_NODE_PERM_WRITE;
+                       sp.access = XS_STATE_NODE_PERM_WRITE;
                        break;
                case XS_PERM_READ | XS_PERM_WRITE:
-                       sn->perms[p].access = XS_STATE_NODE_PERM_BOTH;
+                       sp.access = XS_STATE_NODE_PERM_BOTH;
                        break;
                default:
-                       sn->perms[p].access = XS_STATE_NODE_PERM_NONE;
+                       sp.access = XS_STATE_NODE_PERM_NONE;
                        break;
                }
-               sn->perms[p].flags = (perms[p].perms & XS_PERM_IGNORE)
+               sp.flags = (perms[p].perms & XS_PERM_IGNORE)
                                     ? XS_STATE_NODE_PERM_IGNORE : 0;
-               sn->perms[p].domid = perms[p].id;
-       }
+               sp.domid = perms[p].id;
 
-       if (fwrite(sn->perms, sizeof(*sn->perms), n_perms, fp) != n_perms)
-               return "Dump node permissions error";
+               if (fwrite(&sp, sizeof(sp), 1, fp) != 1)
+                       return "Dump node permissions error";
+       }
 
        return NULL;
 }
 
-static const char *dump_state_node_tree(FILE *fp, char *path)
+struct dump_node_data {
+       FILE *fp;
+       const char *err;
+};
+
+static int dump_state_node_err(struct dump_node_data *data, const char *err)
+{
+       data->err = err;
+       return WALK_TREE_ERROR_STOP;
+}
+
+static int dump_state_node(const void *ctx, struct connection *conn,
+                          struct node *node, void *arg)
 {
-       unsigned int pathlen, childlen, p = 0;
+       struct dump_node_data *data = arg;
+       FILE *fp = data->fp;
+       unsigned int pathlen;
        struct xs_state_record_header head;
        struct xs_state_node sn;
-       TDB_DATA key, data;
-       const struct xs_tdb_record_hdr *hdr;
-       const char *child;
        const char *ret;
 
-       pathlen = strlen(path) + 1;
-
-       set_tdb_key(path, &key);
-       data = tdb_fetch(tdb_ctx, key);
-       if (data.dptr == NULL)
-               return "Error reading node";
-
-       /* Clean up in case of failure. */
-       talloc_steal(path, data.dptr);
-
-       hdr = (void *)data.dptr;
+       pathlen = strlen(node->name) + 1;
 
        head.type = XS_STATE_TYPE_NODE;
        head.length = sizeof(sn);
        sn.conn_id = 0;
        sn.ta_id = 0;
        sn.ta_access = 0;
-       sn.perm_n = hdr->num_perms;
+       sn.perm_n = node->perms.num;
        sn.path_len = pathlen;
-       sn.data_len = hdr->datalen;
-       head.length += hdr->num_perms * sizeof(*sn.perms);
+       sn.data_len = node->datalen;
+       head.length += node->perms.num * sizeof(*sn.perms);
        head.length += pathlen;
-       head.length += hdr->datalen;
+       head.length += node->datalen;
        head.length = ROUNDUP(head.length, 3);
 
        if (fwrite(&head, sizeof(head), 1, fp) != 1)
-               return "Dump node state error";
+               return dump_state_node_err(data, "Dump node head error");
        if (fwrite(&sn, sizeof(sn), 1, fp) != 1)
-               return "Dump node state error";
+               return dump_state_node_err(data, "Dump node state error");
 
-       ret = dump_state_node_perms(fp, &sn, hdr->perms, hdr->num_perms);
+       ret = dump_state_node_perms(fp, node->perms.p, node->perms.num);
        if (ret)
-               return ret;
+               return dump_state_node_err(data, ret);
 
-       if (fwrite(path, pathlen, 1, fp) != 1)
-               return "Dump node path error";
-       if (hdr->datalen &&
-           fwrite(hdr->perms + hdr->num_perms, hdr->datalen, 1, fp) != 1)
-               return "Dump node data error";
+       if (fwrite(node->name, pathlen, 1, fp) != 1)
+               return dump_state_node_err(data, "Dump node path error");
+
+       if (node->datalen && fwrite(node->data, node->datalen, 1, fp) != 1)
+               return dump_state_node_err(data, "Dump node data error");
 
        ret = dump_state_align(fp);
        if (ret)
-               return ret;
-
-       child = (char *)(hdr->perms + hdr->num_perms) + hdr->datalen;
-
-       /*
-        * Use path for constructing children paths.
-        * As we don't write out nodes without having written their parent
-        * already we will never clobber a part of the path we'll need later.
-        */
-       pathlen--;
-       if (path[pathlen - 1] != '/') {
-               path[pathlen] = '/';
-               pathlen++;
-       }
-       while (p < hdr->childlen) {
-               childlen = strlen(child) + 1;
-               if (pathlen + childlen > XENSTORE_ABS_PATH_MAX)
-                       return "Dump node path length error";
-               strcpy(path + pathlen, child);
-               ret = dump_state_node_tree(fp, path);
-               if (ret)
-                       return ret;
-               p += childlen;
-               child += childlen;
-       }
-
-       talloc_free(data.dptr);
+               return dump_state_node_err(data, ret);
 
-       return NULL;
+       return WALK_TREE_OK;
 }
 
 const char *dump_state_nodes(FILE *fp, const void *ctx)
 {
-       char *path;
-
-       path = talloc_size(ctx, XENSTORE_ABS_PATH_MAX);
-       if (!path)
-               return "Path buffer allocation error";
+       struct dump_node_data data = {
+               .fp = fp,
+               .err = "Dump node walk error"
+       };
+       struct walk_funcs walkfuncs = { .enter = dump_state_node };
 
-       strcpy(path, "/");
+       if (walk_node_tree(ctx, NULL, "/", &walkfuncs, &data))
+               return data.err;
 
-       return dump_state_node_tree(fp, path);
+       return NULL;
 }
 
 void read_state_global(const void *ctx, const void *state)
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index f0fd8c3528..3190494bbe 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -326,8 +326,7 @@ const char *dump_state_buffered_data(FILE *fp, const struct 
connection *c,
                                     const struct connection *conn,
                                     struct xs_state_connection *sc);
 const char *dump_state_nodes(FILE *fp, const void *ctx);
-const char *dump_state_node_perms(FILE *fp, struct xs_state_node *sn,
-                                 const struct xs_permissions *perms,
+const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms,
                                  unsigned int n_perms);
 
 void read_state_global(const void *ctx, const void *state);
diff --git a/tools/xenstore/xenstored_domain.c 
b/tools/xenstore/xenstored_domain.c
index 8b503c2dfe..a91cc75ab5 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -1449,7 +1449,7 @@ static const char *dump_state_special_node(FILE *fp, 
const char *name,
        if (fwrite(&sn, sizeof(sn), 1, fp) != 1)
                return "Dump special node error";
 
-       ret = dump_state_node_perms(fp, &sn, perms->p, perms->num);
+       ret = dump_state_node_perms(fp, perms->p, perms->num);
        if (ret)
                return ret;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15



 


Rackspace

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