97374c0
From d1e6dca486599ab914af7b38b3782b237d3d603b Mon Sep 17 00:00:00 2001
97374c0
From: Juergen Gross <jgross@suse.com>
97374c0
Date: Tue, 13 Sep 2022 07:35:11 +0200
97374c0
Subject: tools/xenstore: remove recursion from construct_node()
97374c0
97374c0
In order to reduce stack usage due to recursion, switch
97374c0
construct_node() to use a loop instead.
97374c0
97374c0
This is part of XSA-418 / CVE-2022-42321.
97374c0
97374c0
Reported-by: Julien Grall <dvrabel@amazon.co.uk>
97374c0
Signed-off-by: Juergen Gross <jgross@suse.com>
97374c0
Reviewed-by: Julien Grall <jgrall@amazon.com>
97374c0
97374c0
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
97374c0
index c676ee4e4e4f..3907c35643e9 100644
97374c0
--- a/tools/xenstore/xenstored_core.c
97374c0
+++ b/tools/xenstore/xenstored_core.c
97374c0
@@ -1377,45 +1377,69 @@ static int add_child(const void *ctx, struct node *parent, const char *name)
97374c0
 static struct node *construct_node(struct connection *conn, const void *ctx,
97374c0
 				   const char *name)
97374c0
 {
97374c0
-	struct node *parent, *node;
97374c0
-	char *parentname = get_parent(ctx, name);
97374c0
+	const char **names = NULL;
97374c0
+	unsigned int levels = 0;
97374c0
+	struct node *node = NULL;
97374c0
+	struct node *parent = NULL;
97374c0
+	const char *parentname = talloc_strdup(ctx, name);
97374c0
 
97374c0
 	if (!parentname)
97374c0
 		return NULL;
97374c0
 
97374c0
-	/* If parent doesn't exist, create it. */
97374c0
-	parent = read_node(conn, parentname, parentname);
97374c0
-	if (!parent && errno == ENOENT)
97374c0
-		parent = construct_node(conn, ctx, parentname);
97374c0
-	if (!parent)
97374c0
-		return NULL;
97374c0
+	/* Walk the path up until an existing node is found. */
97374c0
+	while (!parent) {
97374c0
+		names = talloc_realloc(ctx, names, const char *, levels + 1);
97374c0
+		if (!names)
97374c0
+			goto nomem;
97374c0
 
97374c0
-	/* Add child to parent. */
97374c0
-	if (add_child(ctx, parent, name))
97374c0
-		goto nomem;
97374c0
+		/*
97374c0
+		 * names[0] is the name of the node to construct initially,
97374c0
+		 * names[1] is its parent, and so on.
97374c0
+		 */
97374c0
+		names[levels] = parentname;
97374c0
+		parentname = get_parent(ctx, parentname);
97374c0
+		if (!parentname)
97374c0
+			return NULL;
97374c0
 
97374c0
-	/* Allocate node */
97374c0
-	node = talloc(ctx, struct node);
97374c0
-	if (!node)
97374c0
-		goto nomem;
97374c0
-	node->name = talloc_strdup(node, name);
97374c0
-	if (!node->name)
97374c0
-		goto nomem;
97374c0
+		/* Try to read parent node until we found an existing one. */
97374c0
+		parent = read_node(conn, ctx, parentname);
97374c0
+		if (!parent && (errno != ENOENT || !strcmp(parentname, "/")))
97374c0
+			return NULL;
97374c0
 
97374c0
-	/* Inherit permissions, except unprivileged domains own what they create */
97374c0
-	node->perms.num = parent->perms.num;
97374c0
-	node->perms.p = talloc_memdup(node, parent->perms.p,
97374c0
-				      node->perms.num * sizeof(*node->perms.p));
97374c0
-	if (!node->perms.p)
97374c0
-		goto nomem;
97374c0
-	if (domain_is_unprivileged(conn))
97374c0
-		node->perms.p[0].id = conn->id;
97374c0
+		levels++;
97374c0
+	}
97374c0
+
97374c0
+	/* Walk the path down again constructing the missing nodes. */
97374c0
+	for (; levels > 0; levels--) {
97374c0
+		/* Add child to parent. */
97374c0
+		if (add_child(ctx, parent, names[levels - 1]))
97374c0
+			goto nomem;
97374c0
+
97374c0
+		/* Allocate node */
97374c0
+		node = talloc(ctx, struct node);
97374c0
+		if (!node)
97374c0
+			goto nomem;
97374c0
+		node->name = talloc_steal(node, names[levels - 1]);
97374c0
+
97374c0
+		/* Inherit permissions, unpriv domains own what they create. */
97374c0
+		node->perms.num = parent->perms.num;
97374c0
+		node->perms.p = talloc_memdup(node, parent->perms.p,
97374c0
+					      node->perms.num *
97374c0
+					      sizeof(*node->perms.p));
97374c0
+		if (!node->perms.p)
97374c0
+			goto nomem;
97374c0
+		if (domain_is_unprivileged(conn))
97374c0
+			node->perms.p[0].id = conn->id;
97374c0
+
97374c0
+		/* No children, no data */
97374c0
+		node->children = node->data = NULL;
97374c0
+		node->childlen = node->datalen = 0;
97374c0
+		node->acc.memory = 0;
97374c0
+		node->parent = parent;
97374c0
+
97374c0
+		parent = node;
97374c0
+	}
97374c0
 
97374c0
-	/* No children, no data */
97374c0
-	node->children = node->data = NULL;
97374c0
-	node->childlen = node->datalen = 0;
97374c0
-	node->acc.memory = 0;
97374c0
-	node->parent = parent;
97374c0
 	return node;
97374c0
 
97374c0
 nomem: