24e155b
From cddf74031b3c8a108e8fd7db0bf56e9c2809d3e2 Mon Sep 17 00:00:00 2001
24e155b
From: Juergen Gross <jgross@suse.com>
24e155b
Date: Thu, 11 Jun 2020 16:12:45 +0200
24e155b
Subject: [PATCH 09/10] tools/xenstore: allow special watches for privileged
24e155b
 callers only
24e155b
24e155b
The special watches "@introduceDomain" and "@releaseDomain" should be
24e155b
allowed for privileged callers only, as they allow to gain information
24e155b
about presence of other guests on the host. So send watch events for
24e155b
those watches via privileged connections only.
24e155b
24e155b
In order to allow for disaggregated setups where e.g. driver domains
24e155b
need to make use of those special watches add support for calling
24e155b
"set permissions" for those special nodes, too.
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
 docs/misc/xenstore.txt            |  5 +++
24e155b
 tools/xenstore/xenstored_core.c   | 27 ++++++++------
24e155b
 tools/xenstore/xenstored_core.h   |  2 ++
24e155b
 tools/xenstore/xenstored_domain.c | 60 +++++++++++++++++++++++++++++++
24e155b
 tools/xenstore/xenstored_domain.h |  5 +++
24e155b
 tools/xenstore/xenstored_watch.c  |  4 +++
24e155b
 6 files changed, 93 insertions(+), 10 deletions(-)
24e155b
24e155b
diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
24e155b
index 6f8569d5760f..32969eb3fecd 100644
24e155b
--- a/docs/misc/xenstore.txt
24e155b
+++ b/docs/misc/xenstore.txt
24e155b
@@ -170,6 +170,9 @@ SET_PERMS		<path>|<perm-as-string>|+?
24e155b
 		n<domid>	no access
24e155b
 	See http://wiki.xen.org/wiki/XenBus section
24e155b
 	`Permissions' for details of the permissions system.
24e155b
+	It is possible to set permissions for the special watch paths
24e155b
+	"@introduceDomain" and "@releaseDomain" to enable receiving those
24e155b
+	watches in unprivileged domains.
24e155b
 
24e155b
 ---------- Watches ----------
24e155b
 
24e155b
@@ -194,6 +197,8 @@ WATCH			<wpath>|<token>|?
24e155b
 	    @releaseDomain 	occurs on any domain crash or
24e155b
 				shutdown, and also on RELEASE
24e155b
 				and domain destruction
24e155b
+	<wspecial> events are sent to privileged callers or explicitly
24e155b
+	via SET_PERMS enabled domains only.
24e155b
 
24e155b
 	When a watch is first set up it is triggered once straight
24e155b
 	away, with <path> equal to <wpath>.  Watches may be triggered
24e155b
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
24e155b
index fe9943113b9f..720bec269dd3 100644
24e155b
--- a/tools/xenstore/xenstored_core.c
24e155b
+++ b/tools/xenstore/xenstored_core.c
24e155b
@@ -468,8 +468,8 @@ static int write_node(struct connection *conn, struct node *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
-				       const struct node_perms *perms)
24e155b
+enum xs_perm_type perm_for_conn(struct connection *conn,
24e155b
+				const struct node_perms *perms)
24e155b
 {
24e155b
 	unsigned int i;
24e155b
 	enum xs_perm_type mask = XS_PERM_READ|XS_PERM_WRITE|XS_PERM_OWNER;
24e155b
@@ -1245,22 +1245,29 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
24e155b
 	if (perms.num < 2)
24e155b
 		return EINVAL;
24e155b
 
24e155b
-	/* First arg is node name. */
24e155b
-	/* We must own node to do this (tools can do this too). */
24e155b
-	node = get_node_canonicalized(conn, in, in->buffer, &name,
24e155b
-				      XS_PERM_WRITE | XS_PERM_OWNER);
24e155b
-	if (!node)
24e155b
-		return errno;
24e155b
-
24e155b
 	permstr = in->buffer + strlen(in->buffer) + 1;
24e155b
 	perms.num--;
24e155b
 
24e155b
-	perms.p = talloc_array(node, struct xs_permissions, perms.num);
24e155b
+	perms.p = talloc_array(in, struct xs_permissions, perms.num);
24e155b
 	if (!perms.p)
24e155b
 		return ENOMEM;
24e155b
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
24e155b
 		return errno;
24e155b
 
24e155b
+	/* First arg is node name. */
24e155b
+	if (strstarts(in->buffer, "@")) {
24e155b
+		if (set_perms_special(conn, in->buffer, &perms))
24e155b
+			return errno;
24e155b
+		send_ack(conn, XS_SET_PERMS);
24e155b
+		return 0;
24e155b
+	}
24e155b
+
24e155b
+	/* We must own node to do this (tools can do this too). */
24e155b
+	node = get_node_canonicalized(conn, in, in->buffer, &name,
24e155b
+				      XS_PERM_WRITE | XS_PERM_OWNER);
24e155b
+	if (!node)
24e155b
+		return errno;
24e155b
+
24e155b
 	/* Unprivileged domains may not change the owner. */
24e155b
 	if (domain_is_unprivileged(conn) &&
24e155b
 	    perms.p[0].id != node->perms.p[0].id)
24e155b
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
24e155b
index 193d93142636..f3da6bbc943d 100644
24e155b
--- a/tools/xenstore/xenstored_core.h
24e155b
+++ b/tools/xenstore/xenstored_core.h
24e155b
@@ -165,6 +165,8 @@ struct node *get_node(struct connection *conn,
24e155b
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
24e155b
 void check_store(void);
24e155b
 void corrupt(struct connection *conn, const char *fmt, ...);
24e155b
+enum xs_perm_type perm_for_conn(struct connection *conn,
24e155b
+				const struct node_perms *perms);
24e155b
 
24e155b
 /* Is this a valid node name? */
24e155b
 bool is_valid_nodename(const char *node);
24e155b
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
24e155b
index dc51cdfa9aa7..7afabe0ae084 100644
24e155b
--- a/tools/xenstore/xenstored_domain.c
24e155b
+++ b/tools/xenstore/xenstored_domain.c
24e155b
@@ -41,6 +41,9 @@ static evtchn_port_t virq_port;
24e155b
 
24e155b
 xenevtchn_handle *xce_handle = NULL;
24e155b
 
24e155b
+static struct node_perms dom_release_perms;
24e155b
+static struct node_perms dom_introduce_perms;
24e155b
+
24e155b
 struct domain
24e155b
 {
24e155b
 	struct list_head list;
24e155b
@@ -589,6 +592,59 @@ void restore_existing_connections(void)
24e155b
 {
24e155b
 }
24e155b
 
24e155b
+static int set_dom_perms_default(struct node_perms *perms)
24e155b
+{
24e155b
+	perms->num = 1;
24e155b
+	perms->p = talloc_array(NULL, struct xs_permissions, perms->num);
24e155b
+	if (!perms->p)
24e155b
+		return -1;
24e155b
+	perms->p->id = 0;
24e155b
+	perms->p->perms = XS_PERM_NONE;
24e155b
+
24e155b
+	return 0;
24e155b
+}
24e155b
+
24e155b
+static struct node_perms *get_perms_special(const char *name)
24e155b
+{
24e155b
+	if (!strcmp(name, "@releaseDomain"))
24e155b
+		return &dom_release_perms;
24e155b
+	if (!strcmp(name, "@introduceDomain"))
24e155b
+		return &dom_introduce_perms;
24e155b
+	return NULL;
24e155b
+}
24e155b
+
24e155b
+int set_perms_special(struct connection *conn, const char *name,
24e155b
+		      struct node_perms *perms)
24e155b
+{
24e155b
+	struct node_perms *p;
24e155b
+
24e155b
+	p = get_perms_special(name);
24e155b
+	if (!p)
24e155b
+		return EINVAL;
24e155b
+
24e155b
+	if ((perm_for_conn(conn, p) & (XS_PERM_WRITE | XS_PERM_OWNER)) !=
24e155b
+	    (XS_PERM_WRITE | XS_PERM_OWNER))
24e155b
+		return EACCES;
24e155b
+
24e155b
+	p->num = perms->num;
24e155b
+	talloc_free(p->p);
24e155b
+	p->p = perms->p;
24e155b
+	talloc_steal(NULL, perms->p);
24e155b
+
24e155b
+	return 0;
24e155b
+}
24e155b
+
24e155b
+bool check_perms_special(const char *name, struct connection *conn)
24e155b
+{
24e155b
+	struct node_perms *p;
24e155b
+
24e155b
+	p = get_perms_special(name);
24e155b
+	if (!p)
24e155b
+		return false;
24e155b
+
24e155b
+	return perm_for_conn(conn, p) & XS_PERM_READ;
24e155b
+}
24e155b
+
24e155b
 static int dom0_init(void) 
24e155b
 { 
24e155b
 	evtchn_port_t port;
24e155b
@@ -610,6 +666,10 @@ static int dom0_init(void)
24e155b
 
24e155b
 	xenevtchn_notify(xce_handle, dom0->port);
24e155b
 
24e155b
+	if (set_dom_perms_default(&dom_release_perms) ||
24e155b
+	    set_dom_perms_default(&dom_introduce_perms))
24e155b
+		return -1;
24e155b
+
24e155b
 	return 0; 
24e155b
 }
24e155b
 
24e155b
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
24e155b
index 56ae01597475..259183962a9c 100644
24e155b
--- a/tools/xenstore/xenstored_domain.h
24e155b
+++ b/tools/xenstore/xenstored_domain.h
24e155b
@@ -65,6 +65,11 @@ void domain_watch_inc(struct connection *conn);
24e155b
 void domain_watch_dec(struct connection *conn);
24e155b
 int domain_watch(struct connection *conn);
24e155b
 
24e155b
+/* Special node permission handling. */
24e155b
+int set_perms_special(struct connection *conn, const char *name,
24e155b
+		      struct node_perms *perms);
24e155b
+bool check_perms_special(const char *name, struct connection *conn);
24e155b
+
24e155b
 /* Write rate limiting */
24e155b
 
24e155b
 #define WRL_FACTOR   1000 /* for fixed-point arithmetic */
24e155b
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
24e155b
index 3836675459fa..f4e289362eb6 100644
24e155b
--- a/tools/xenstore/xenstored_watch.c
24e155b
+++ b/tools/xenstore/xenstored_watch.c
24e155b
@@ -133,6 +133,10 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
24e155b
 
24e155b
 	/* Create an event for each watch. */
24e155b
 	list_for_each_entry(i, &connections, list) {
24e155b
+		/* introduce/release domain watches */
24e155b
+		if (check_special_event(name) && !check_perms_special(name, i))
24e155b
+			continue;
24e155b
+
24e155b
 		list_for_each_entry(watch, &i->watches, list) {
24e155b
 			if (exact) {
24e155b
 				if (streq(name, watch->node))
24e155b
-- 
24e155b
2.17.1
24e155b