From 2d4f410899bf59e112c107f371c3d164f8a592f8 Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Thu, 11 Jun 2020 16:12:44 +0200
Subject: [PATCH 08/10] tools/xenstore: introduce node_perms structure

There are several places in xenstored using a permission array and the
size of that array. Introduce a new struct node_perms containing both.

This is part of XSA-115.

Signed-off-by: Juergen Gross <jgross@suse.com>
Acked-by: Julien Grall <jgrall@amazon.com>
Reviewed-by: Paul Durrant <paul@xen.org>
---
 tools/xenstore/xenstored_core.c   | 79 +++++++++++++++----------------
 tools/xenstore/xenstored_core.h   |  8 +++-
 tools/xenstore/xenstored_domain.c | 12 ++---
 3 files changed, 50 insertions(+), 49 deletions(-)

Index: xen-4.0.3-testing/tools/xenstore/xenstored_core.c
===================================================================
--- xen-4.0.3-testing.orig/tools/xenstore/xenstored_core.c
+++ xen-4.0.3-testing/tools/xenstore/xenstored_core.c
@@ -373,14 +373,14 @@ static struct node *read_node(struct con
 	/* Datalen, childlen, number of permissions */
 	hdr = (void *)data.dptr;
 	node->generation = hdr->generation;
-	node->num_perms = hdr->num_perms;
+	node->perms.num = hdr->num_perms;
 	node->datalen = hdr->datalen;
 	node->childlen = hdr->childlen;
 
 	/* Permissions are struct xs_permissions. */
-	node->perms = hdr->perms;
+	node->perms.p = hdr->perms;
 	/* Data is binary blob (usually ascii, no nul). */
-	node->data = node->perms + node->num_perms;
+	node->data = node->perms.p + node->perms.num;
 	/* Children is strings, nul separated. */
 	node->children = node->data + node->datalen;
 
@@ -397,7 +397,7 @@ int write_node_raw(struct connection *co
 	struct xs_tdb_record_hdr *hdr;
 
 	data.dsize = sizeof(*hdr)
-		+ node->num_perms*sizeof(node->perms[0])
+		+ node->perms.num * sizeof(node->perms.p[0])
 		+ node->datalen + node->childlen;
 
 	if (!no_quota_check && domain_is_unprivileged(conn) &&
@@ -409,12 +409,13 @@ int write_node_raw(struct connection *co
 	data.dptr = talloc_size(node, data.dsize);
 	hdr = (void *)data.dptr;
 	hdr->generation = node->generation;
-	hdr->num_perms = node->num_perms;
+	hdr->num_perms = node->perms.num;
 	hdr->datalen = node->datalen;
 	hdr->childlen = node->childlen;
 
-	memcpy(hdr->perms, node->perms, node->num_perms*sizeof(node->perms[0]));
-	p = hdr->perms + node->num_perms;
+	memcpy(hdr->perms, node->perms.p,
+	       node->perms.num * sizeof(*node->perms.p));
+	p = hdr->perms + node->perms.num;
 	memcpy(p, node->data, node->datalen);
 	p += node->datalen;
 	memcpy(p, node->children, node->childlen);
@@ -440,8 +441,7 @@ static int write_node(struct connection
 }
 
 static enum xs_perm_type perm_for_conn(struct connection *conn,
-				       struct xs_permissions *perms,
-				       unsigned int num)
+				       const struct node_perms *perms)
 {
 	unsigned int i;
 	enum xs_perm_type mask = XS_PERM_READ|XS_PERM_WRITE|XS_PERM_OWNER;
@@ -450,16 +450,16 @@ static enum xs_perm_type perm_for_conn(s
 		mask &= ~XS_PERM_WRITE;
 
 	/* Owners and tools get it all... */
-	if (!conn->id || perms[0].id == conn->id
-                || (conn->target && perms[0].id == conn->target->id))
+	if (!conn->id || perms->p[0].id == conn->id
+                || (conn->target && perms->p[0].id == conn->target->id))
 		return (XS_PERM_READ|XS_PERM_WRITE|XS_PERM_OWNER) & mask;
 
-	for (i = 1; i < num; i++)
-		if (perms[i].id == conn->id
-                        || (conn->target && perms[i].id == conn->target->id))
-			return perms[i].perms & mask;
+	for (i = 1; i < perms->num; i++)
+		if (perms->p[i].id == conn->id
+                        || (conn->target && perms->p[i].id == conn->target->id))
+			return perms->p[i].perms & mask;
 
-	return perms[0].perms & mask;
+	return perms->p[0].perms & mask;
 }
 
 /*
@@ -506,7 +506,7 @@ static int ask_parents(struct connection
 		return 0;
  	}
 
-	*perm = perm_for_conn(conn, node->perms, node->num_perms);
+	*perm = perm_for_conn(conn, &node->perms);
 	return 0;
 }
 
@@ -552,8 +552,7 @@ struct node *get_node(struct connection
 	node = read_node(conn, ctx, name);
 	/* If we don't have permission, we don't have node. */
 	if (node) {
-		if ((perm_for_conn(conn, node->perms, node->num_perms) & perm)
-		    != perm) {
+		if ((perm_for_conn(conn, &node->perms) & perm) != perm) {
 			errno = EACCES;
 			node = NULL;
 		}
@@ -724,16 +723,15 @@ const char *onearg(struct buffered_data
 	return in->buffer;
 }
 
-static char *perms_to_strings(const void *ctx,
-			      struct xs_permissions *perms, unsigned int num,
+static char *perms_to_strings(const void *ctx, const struct node_perms *perms,
 			      unsigned int *len)
 {
 	unsigned int i;
 	char *strings = NULL;
 	char buffer[MAX_STRLEN(unsigned int) + 1];
 
-	for (*len = 0, i = 0; i < num; i++) {
-		if (!xs_perm_to_string(&perms[i], buffer, sizeof(buffer)))
+	for (*len = 0, i = 0; i < perms->num; i++) {
+		if (!xs_perm_to_string(&perms->p[i], buffer, sizeof(buffer)))
 			return NULL;
 
 		strings = talloc_realloc(ctx, strings, char,
@@ -912,13 +910,13 @@ static struct node *construct_node(struc
 		goto nomem;
 
 	/* Inherit permissions, except domains own what they create */
-	node->num_perms = parent->num_perms;
-	node->perms = talloc_memdup(node, parent->perms,
-				    node->num_perms * sizeof(node->perms[0]));
-	if (!node->perms)
+	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 (conn && conn->id)
-		node->perms[0].id = conn->id;
+		node->perms.p[0].id = conn->id;
 
 	/* No children, no data */
 	node->children = node->data = NULL;
@@ -1197,7 +1195,7 @@ static int do_get_perms(struct connectio
 	if (!node)
 		return errno;
 
-	strings = perms_to_strings(node, node->perms, node->num_perms, &len);
+	strings = perms_to_strings(node, &node->perms, &len);
 	if (!strings)
 		return errno;
 
@@ -1208,13 +1206,12 @@ static int do_get_perms(struct connectio
 
 static int do_set_perms(struct connection *conn, struct buffered_data *in)
 {
-	unsigned int num;
-	struct xs_permissions *perms;
+	struct node_perms perms;
 	char *name, *permstr;
 	struct node *node;
 
-	num = xs_count_strings(in->buffer, in->used);
-	if (num < 2)
+	perms.num = xs_count_strings(in->buffer, in->used);
+	if (perms.num < 2)
 		return EINVAL;
 
 	/* First arg is node name. */
@@ -1225,21 +1222,21 @@ static int do_set_perms(struct connectio
 		return errno;
 
 	permstr = in->buffer + strlen(in->buffer) + 1;
-	num--;
+	perms.num--;
 
-	perms = talloc_array(node, struct xs_permissions, num);
-	if (!perms)
+	perms.p = talloc_array(node, struct xs_permissions, perms.num);
+	if (!perms.p)
 		return ENOMEM;
-	if (!xs_strings_to_perms(perms, num, permstr))
+	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
 		return errno;
 
 	/* Unprivileged domains may not change the owner. */
-	if (domain_is_unprivileged(conn) && perms[0].id != node->perms[0].id)
+	if (domain_is_unprivileged(conn) &&
+	    perms.p[0].id != node->perms.p[0].id)
 		return EPERM;
 
 	domain_entry_dec(conn, node);
 	node->perms = perms;
-	node->num_perms = num;
 	domain_entry_inc(conn, node);
 
 	if (write_node(conn, node, false))
@@ -1510,8 +1507,8 @@ static void manual_node(const char *name
 		barf_perror("Could not allocate initial node %s", name);
 
 	node->name = name;
-	node->perms = &perms;
-	node->num_perms = 1;
+	node->perms.p = &perms;
+	node->perms.num = 1;
 	node->children = (char *)child;
 	if (child)
 		node->childlen = strlen(child) + 1;
Index: xen-4.0.3-testing/tools/xenstore/xenstored_core.h
===================================================================
--- xen-4.0.3-testing.orig/tools/xenstore/xenstored_core.h
+++ xen-4.0.3-testing/tools/xenstore/xenstored_core.h
@@ -107,6 +107,11 @@ struct connection
 };
 extern struct list_head connections;
 
+struct node_perms {
+	unsigned int num;
+	struct xs_permissions *p;
+};
+
 struct node {
 	const char *name;
 
@@ -118,8 +123,7 @@ struct node {
 #define NO_GENERATION ~((uint64_t)0)
 
 	/* Permissions. */
-	unsigned int num_perms;
-	struct xs_permissions *perms;
+	struct node_perms perms;
 
 	/* Contents. */
 	unsigned int datalen;
Index: xen-4.0.3-testing/tools/xenstore/xenstored_domain.c
===================================================================
--- xen-4.0.3-testing.orig/tools/xenstore/xenstored_domain.c
+++ xen-4.0.3-testing/tools/xenstore/xenstored_domain.c
@@ -623,12 +623,12 @@ void domain_entry_inc(struct connection
 	if (!conn)
 		return;
 
-	if (node->perms && node->perms[0].id != conn->id) {
+	if (node->perms.p && node->perms.p[0].id != conn->id) {
 		if (conn->transaction) {
 			transaction_entry_inc(conn->transaction,
-				node->perms[0].id);
+				node->perms.p[0].id);
 		} else {
-			d = find_domain_by_domid(node->perms[0].id);
+			d = find_domain_by_domid(node->perms.p[0].id);
 			if (d)
 				d->nbentry++;
 		}
@@ -649,12 +649,12 @@ void domain_entry_dec(struct connection
 	if (!conn)
 		return;
 
-	if (node->perms && node->perms[0].id != conn->id) {
+	if (node->perms.p && node->perms.p[0].id != conn->id) {
 		if (conn->transaction) {
 			transaction_entry_dec(conn->transaction,
-				node->perms[0].id);
+				node->perms.p[0].id);
 		} else {
-			d = find_domain_by_domid(node->perms[0].id);
+			d = find_domain_by_domid(node->perms.p[0].id);
 			if (d && d->nbentry)
 				d->nbentry--;
 		}
