diff options
Diffstat (limited to '0117-tools-xenstore-use-treewalk-for-creating-node-record.patch')
-rw-r--r-- | 0117-tools-xenstore-use-treewalk-for-creating-node-record.patch | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/0117-tools-xenstore-use-treewalk-for-creating-node-record.patch b/0117-tools-xenstore-use-treewalk-for-creating-node-record.patch new file mode 100644 index 0000000..6271169 --- /dev/null +++ b/0117-tools-xenstore-use-treewalk-for-creating-node-record.patch @@ -0,0 +1,242 @@ +From 84674f206778e9b3d8d67c6c76aa8094a262d5ec Mon Sep 17 00:00:00 2001 +From: Juergen Gross <jgross@suse.com> +Date: Tue, 13 Sep 2022 07:35:12 +0200 +Subject: [PATCH 117/126] 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@suse.com> +Reviewed-by: Julien Grall <jgrall@amazon.com> +(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 9576411757fa..e8cdfeef50c7 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) + { +- unsigned int pathlen, childlen, p = 0; ++ data->err = err; ++ return WALK_TREE_ERROR_STOP; ++} ++ ++static int dump_state_node(const void *ctx, struct connection *conn, ++ struct node *node, void *arg) ++{ ++ 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; ++ return dump_state_node_err(data, 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 NULL; ++ return WALK_TREE_OK; + } + + const char *dump_state_nodes(FILE *fp, const void *ctx) + { +- char *path; ++ struct dump_node_data data = { ++ .fp = fp, ++ .err = "Dump node walk error" ++ }; ++ struct walk_funcs walkfuncs = { .enter = dump_state_node }; + +- path = talloc_size(ctx, XENSTORE_ABS_PATH_MAX); +- if (!path) +- return "Path buffer allocation error"; ++ if (walk_node_tree(ctx, NULL, "/", &walkfuncs, &data)) ++ return data.err; + +- strcpy(path, "/"); +- +- 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 f0fd8c352857..3190494bbeb5 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 8b503c2dfe07..a91cc75ab59b 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; + +-- +2.37.4 + |