summaryrefslogtreecommitdiff
blob: 72aebfd955ca3da38b6eb94980a7130ef4410757 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
From 074b32e47174a30bb751f2e2c07628eb56117eb8 Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Tue, 13 Sep 2022 07:35:11 +0200
Subject: [PATCH 72/87] tools/xenstore: remove recursion from construct_node()

In order to reduce stack usage due to recursion, switch
construct_node() to use a loop instead.

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 da8ee25d02a5447ba39a9800ee2a710ae1f54222)
---
 tools/xenstore/xenstored_core.c | 86 +++++++++++++++++++++------------
 1 file changed, 55 insertions(+), 31 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index c676ee4e4e4f..3907c35643e9 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1377,45 +1377,69 @@ static int add_child(const void *ctx, struct node *parent, const char *name)
 static struct node *construct_node(struct connection *conn, const void *ctx,
 				   const char *name)
 {
-	struct node *parent, *node;
-	char *parentname = get_parent(ctx, name);
+	const char **names = NULL;
+	unsigned int levels = 0;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+	const char *parentname = talloc_strdup(ctx, name);
 
 	if (!parentname)
 		return NULL;
 
-	/* If parent doesn't exist, create it. */
-	parent = read_node(conn, parentname, parentname);
-	if (!parent && errno == ENOENT)
-		parent = construct_node(conn, ctx, parentname);
-	if (!parent)
-		return NULL;
+	/* Walk the path up until an existing node is found. */
+	while (!parent) {
+		names = talloc_realloc(ctx, names, const char *, levels + 1);
+		if (!names)
+			goto nomem;
 
-	/* Add child to parent. */
-	if (add_child(ctx, parent, name))
-		goto nomem;
+		/*
+		 * names[0] is the name of the node to construct initially,
+		 * names[1] is its parent, and so on.
+		 */
+		names[levels] = parentname;
+		parentname = get_parent(ctx, parentname);
+		if (!parentname)
+			return NULL;
 
-	/* Allocate node */
-	node = talloc(ctx, struct node);
-	if (!node)
-		goto nomem;
-	node->name = talloc_strdup(node, name);
-	if (!node->name)
-		goto nomem;
+		/* Try to read parent node until we found an existing one. */
+		parent = read_node(conn, ctx, parentname);
+		if (!parent && (errno != ENOENT || !strcmp(parentname, "/")))
+			return NULL;
 
-	/* Inherit permissions, except unprivileged domains own what they create */
-	node->perms.num = parent->perms.num;
-	node->perms.p = talloc_memdup(node, parent->perms.p,
-				      node->perms.num * sizeof(*node->perms.p));
-	if (!node->perms.p)
-		goto nomem;
-	if (domain_is_unprivileged(conn))
-		node->perms.p[0].id = conn->id;
+		levels++;
+	}
+
+	/* Walk the path down again constructing the missing nodes. */
+	for (; levels > 0; levels--) {
+		/* Add child to parent. */
+		if (add_child(ctx, parent, names[levels - 1]))
+			goto nomem;
+
+		/* Allocate node */
+		node = talloc(ctx, struct node);
+		if (!node)
+			goto nomem;
+		node->name = talloc_steal(node, names[levels - 1]);
+
+		/* Inherit permissions, unpriv domains own what they create. */
+		node->perms.num = parent->perms.num;
+		node->perms.p = talloc_memdup(node, parent->perms.p,
+					      node->perms.num *
+					      sizeof(*node->perms.p));
+		if (!node->perms.p)
+			goto nomem;
+		if (domain_is_unprivileged(conn))
+			node->perms.p[0].id = conn->id;
+
+		/* No children, no data */
+		node->children = node->data = NULL;
+		node->childlen = node->datalen = 0;
+		node->acc.memory = 0;
+		node->parent = parent;
+
+		parent = node;
+	}
 
-	/* No children, no data */
-	node->children = node->data = NULL;
-	node->childlen = node->datalen = 0;
-	node->acc.memory = 0;
-	node->parent = parent;
 	return node;
 
 nomem:
-- 
2.37.4