24e155b
From e92f3dfeaae21a335e666c9247954424e34e5c56 Mon Sep 17 00:00:00 2001
24e155b
From: Juergen Gross <jgross@suse.com>
24e155b
Date: Thu, 11 Jun 2020 16:12:37 +0200
24e155b
Subject: [PATCH 01/10] tools/xenstore: allow removing child of a node
24e155b
 exceeding quota
24e155b
24e155b
An unprivileged user of Xenstore is not allowed to write nodes with a
24e155b
size exceeding a global quota, while privileged users like dom0 are
24e155b
allowed to write such nodes. The size of a node is the needed space
24e155b
to store all node specific data, this includes the names of all
24e155b
children of the node.
24e155b
24e155b
When deleting a node its parent has to be modified by removing the
24e155b
name of the to be deleted child from it.
24e155b
24e155b
This results in the strange situation that an unprivileged owner of a
24e155b
node might not succeed in deleting that node in case its parent is
24e155b
exceeding the quota of that unprivileged user (it might have been
24e155b
written by dom0), as the user is not allowed to write the updated
24e155b
parent node.
24e155b
24e155b
Fix that by not checking the quota when writing a node for the
24e155b
purpose of removing a child's name only.
24e155b
24e155b
The same applies to transaction handling: a node being read during a
24e155b
transaction is written to the transaction specific area and it should
24e155b
not be tested for exceeding the quota, as it might not be owned by
24e155b
the reader and presumably the original write would have failed if the
24e155b
node is owned by the reader.
24e155b
24e155b
This is part of XSA-115.
24e155b
24e155b
Signed-off-by: Juergen Gross <jgross@suse.com>
24e155b
Reviewed-by: Julien Grall <jgrall@amazon.com>
24e155b
Reviewed-by: Paul Durrant <paul@xen.org>
24e155b
---
24e155b
 tools/xenstore/xenstored_core.c        | 20 +++++++++++---------
24e155b
 tools/xenstore/xenstored_core.h        |  3 ++-
24e155b
 tools/xenstore/xenstored_transaction.c |  2 +-
24e155b
 3 files changed, 14 insertions(+), 11 deletions(-)
24e155b
24e155b
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
24e155b
index 97ceabf9642d..b43e1018babd 100644
24e155b
--- a/tools/xenstore/xenstored_core.c
24e155b
+++ b/tools/xenstore/xenstored_core.c
24e155b
@@ -417,7 +417,8 @@ static struct node *read_node(struct connection *conn, const void *ctx,
24e155b
 	return node;
24e155b
 }
24e155b
 
24e155b
-int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node)
24e155b
+int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
24e155b
+		   bool no_quota_check)
24e155b
 {
24e155b
 	TDB_DATA data;
24e155b
 	void *p;
24e155b
@@ -427,7 +428,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node)
24e155b
 		+ node->num_perms*sizeof(node->perms[0])
24e155b
 		+ node->datalen + node->childlen;
24e155b
 
24e155b
-	if (domain_is_unprivileged(conn) &&
24e155b
+	if (!no_quota_check && domain_is_unprivileged(conn) &&
24e155b
 	    data.dsize >= quota_max_entry_size) {
24e155b
 		errno = ENOSPC;
24e155b
 		return errno;
24e155b
@@ -455,14 +456,15 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node)
24e155b
 	return 0;
24e155b
 }
24e155b
 
24e155b
-static int write_node(struct connection *conn, struct node *node)
24e155b
+static int write_node(struct connection *conn, struct node *node,
24e155b
+		      bool no_quota_check)
24e155b
 {
24e155b
 	TDB_DATA key;
24e155b
 
24e155b
 	if (access_node(conn, node, NODE_ACCESS_WRITE, &key))
24e155b
 		return errno;
24e155b
 
24e155b
-	return write_node_raw(conn, &key, node);
24e155b
+	return write_node_raw(conn, &key, node, no_quota_check);
24e155b
 }
24e155b
 
24e155b
 static enum xs_perm_type perm_for_conn(struct connection *conn,
24e155b
@@ -999,7 +1001,7 @@ static struct node *create_node(struct connection *conn, const void *ctx,
24e155b
 	/* We write out the nodes down, setting destructor in case
24e155b
 	 * something goes wrong. */
24e155b
 	for (i = node; i; i = i->parent) {
24e155b
-		if (write_node(conn, i)) {
24e155b
+		if (write_node(conn, i, false)) {
24e155b
 			domain_entry_dec(conn, i);
24e155b
 			return NULL;
24e155b
 		}
24e155b
@@ -1039,7 +1041,7 @@ static int do_write(struct connection *conn, struct buffered_data *in)
24e155b
 	} else {
24e155b
 		node->data = in->buffer + offset;
24e155b
 		node->datalen = datalen;
24e155b
-		if (write_node(conn, node))
24e155b
+		if (write_node(conn, node, false))
24e155b
 			return errno;
24e155b
 	}
24e155b
 
24e155b
@@ -1115,7 +1117,7 @@ static int remove_child_entry(struct connection *conn, struct node *node,
24e155b
 	size_t childlen = strlen(node->children + offset);
24e155b
 	memdel(node->children, offset, childlen + 1, node->childlen);
24e155b
 	node->childlen -= childlen + 1;
24e155b
-	return write_node(conn, node);
24e155b
+	return write_node(conn, node, true);
24e155b
 }
24e155b
 
24e155b
 
24e155b
@@ -1254,7 +1256,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
24e155b
 	node->num_perms = num;
24e155b
 	domain_entry_inc(conn, node);
24e155b
 
24e155b
-	if (write_node(conn, node))
24e155b
+	if (write_node(conn, node, false))
24e155b
 		return errno;
24e155b
 
24e155b
 	fire_watches(conn, in, name, false);
24e155b
@@ -1514,7 +1516,7 @@ static void manual_node(const char *name, const char *child)
24e155b
 	if (child)
24e155b
 		node->childlen = strlen(child) + 1;
24e155b
 
24e155b
-	if (write_node(NULL, node))
24e155b
+	if (write_node(NULL, node, false))
24e155b
 		barf_perror("Could not create initial node %s", name);
24e155b
 	talloc_free(node);
24e155b
 }
24e155b
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
24e155b
index 56a279cfbb47..3cb1c235a101 100644
24e155b
--- a/tools/xenstore/xenstored_core.h
24e155b
+++ b/tools/xenstore/xenstored_core.h
24e155b
@@ -149,7 +149,8 @@ void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
24e155b
 char *xenstore_canonicalize(struct connection *conn, const void *ctx, const char *node);
24e155b
 
24e155b
 /* Write a node to the tdb data base. */
24e155b
-int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node);
24e155b
+int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
24e155b
+		   bool no_quota_check);
24e155b
 
24e155b
 /* Get this node, checking we have permissions. */
24e155b
 struct node *get_node(struct connection *conn,
24e155b
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
24e155b
index 2824f7b359b8..e87897573469 100644
24e155b
--- a/tools/xenstore/xenstored_transaction.c
24e155b
+++ b/tools/xenstore/xenstored_transaction.c
24e155b
@@ -276,7 +276,7 @@ int access_node(struct connection *conn, struct node *node,
24e155b
 			i->check_gen = true;
24e155b
 			if (node->generation != NO_GENERATION) {
24e155b
 				set_tdb_key(trans_name, &local_key);
24e155b
-				ret = write_node_raw(conn, &local_key, node);
24e155b
+				ret = write_node_raw(conn, &local_key, node, true);
24e155b
 				if (ret)
24e155b
 					goto err;
24e155b
 				i->ta_node = true;
24e155b
-- 
24e155b
2.17.1
24e155b