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>
This commit is contained in:
Juergen Gross authored and Andrew Cooper committed 2022-11-01 13:05:44 +00:00
1 parent ea16962053
commit 297ac246a5
1 file changed
+40 -65
+40 -65
View File
@@ -3088,101 +3088,76 @@ const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms,
return NULL;
}
static const char *dump_state_node_tree(FILE *fp, char *path,
unsigned int path_max_len)
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, 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 > path_max_len)
return "Dump node path length error";
strcpy(path + pathlen, child);
ret = dump_state_node_tree(fp, path, path_max_len);
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 + 1);
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, XENSTORE_ABS_PATH_MAX + 1);
return NULL;
}
void read_state_global(const void *ctx, const void *state)
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.