Xen Security Advisory 417 v2 (CVE-2022-42320) - Xenstore: Guests can get access to Xenstore nodes of deleted domains

Xen.org security team posted 1 patch 1 year, 6 months ago
Failed in applying to current master (apply log)
Xen Security Advisory 417 v2 (CVE-2022-42320) - Xenstore: Guests can get access to Xenstore nodes of deleted domains
Posted by Xen.org security team 1 year, 6 months ago
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

            Xen Security Advisory CVE-2022-42320 / XSA-417
                               version 2

 Xenstore: Guests can get access to Xenstore nodes of deleted domains

UPDATES IN VERSION 2
====================

Public release.

ISSUE DESCRIPTION
=================

Access rights of Xenstore nodes are per domid.  When a domain is gone,
there might be Xenstore nodes left with access rights containing the
domid of the removed domain.  This is normally no problem, as those
access right entries will be corrected when such a node is written
later.

There is a small time window when a new domain is created, where the
access rights of a past domain with the same domid as the new one will
be regarded to be still valid, leading to the new domain being able to
get access to a node which was meant to be accessible by the removed
domain.  For this to happen another domain needs to write the node
before the newly created domain is being introduced to Xenstore by
dom0.

IMPACT
======

In some circumstances, it might be possible for a new guest domain to
access resources belonging to a previous domain.  The impact would
depend on the software in use and the configuration, but might include
any of denial of service, information leak, or privilege escalation.

VULNERABLE SYSTEMS
==================

All versions of Xen are in principle vulnerable.

Only systems running the C variant of Xenstore (xenstored or xenstore-
stubdom) are vulnerable.

Systems using the Ocaml variant of Xenstore (oxenstored) are not vulnerable.

Vulnerable systems are only those running software where one domain is
granted access to another's xenstore nodes, without complete cleanup
of those nodes on domain destruction.  No such software is enabled in
default configurations of upstream Xen.

Therefore upstream Xen, without additional management software (in
host or guest(s)), is not vulnerable in the default (host and guest)
configuration.

MITIGATION
==========

Running oxenstored instead of xenstored will avoid the vulnerability.

CREDITS
=======

This issue was discovered by Jürgen Groß of SUSE.

RESOLUTION
==========

Applying the appropriate attached patch resolves this issue.

Note that patches for released versions are generally prepared to
apply to the stable branches, and may not apply cleanly to the most
recent release tarball.  Downstreams are encouraged to update to the
tip of the stable branch before applying these patches.

xsa417.patch           xen-unstable, Xen 4.16.x - 4.13.x

$ sha256sum xsa417*
62b37c77cc97374685d1df31da57809ddd6c9ad2272fb3380555e81dc85f0cd8  xsa417.meta
b0c3bdc1723ead350c86b5a42f5e28445fa331ba5f463d82385fdaeb80119b30  xsa417.patch
$

DEPLOYMENT DURING EMBARGO
=========================

Deployment of the patches and/or mitigations described above (or
others which are substantially similar) is permitted during the
embargo, even on public-facing systems with untrusted guest users and
administrators.

But: Distribution of updated software is prohibited (except to other
members of the predisclosure list).

Predisclosure list members who wish to deploy significantly different
patches and/or mitigations, please contact the Xen Project Security
Team.


(Note: this during-embargo deployment notice is retained in
post-embargo publicly released Xen Project advisories, even though it
is then no longer applicable.  This is to enable the community to have
oversight of the Xen Project Security Team's decisionmaking.)

For more information about permissible uses of embargoed information,
consult the Xen Project community's agreed Security Policy:
  http://www.xenproject.org/security-policy.html
-----BEGIN PGP SIGNATURE-----

iQE/BAEBCAAqFiEEI+MiLBRfRHX6gGCng/4UyVfoK9kFAmNg+6gMHHBncEB4ZW4u
b3JnAAoJEIP+FMlX6CvZCj8H93lp5U3OwMNzzrurILUGMY/N6rcGnuoWqa91FslA
C7PSK+A51TvrODUi7bo3YQ1mImW75NmyasMey7/I78DUdHuRwj4L9XOI+W9J5ePk
oSVBja6jUC6LawLxj21DBP1rhufqVnJ0lOsO6rK+v/awJOkANH1nstUksqvxPmKa
ESMDudyo4+2wWH/DKizq6FYexyEQ/rlCktWZTQi1T1PXFX5xMOk+dzd+SSxifX/7
BSLc/HdRzNt1UemKtKvw7KJqCys0Sw8EWAwu6vpQCqczNbkM8CmhzapSWc+IyCZ3
RMOxk9OuW8+6/9D0s4oqWJ7lV4UfW1kZ8euPeybEhLXo5w==
=Kkzx
-----END PGP SIGNATURE-----
{
  "XSA": 417,
  "SupportedVersions": [
    "master",
    "4.16",
    "4.15",
    "4.14",
    "4.13"
  ],
  "Trees": [
    "xen"
  ],
  "Recipes": {
    "4.13": {
      "Recipes": {
        "xen": {
          "StableRef": "0be63c2615b268001f7cc9b72ce25eed952737dc",
          "Prereqs": [
            414,
            415,
            326,
            416
          ],
          "Patches": [
            "xsa417.patch"
          ]
        }
      }
    },
    "4.14": {
      "Recipes": {
        "xen": {
          "StableRef": "016de62747b26ead5a5c763b640fe8e205cd182b",
          "Prereqs": [
            414,
            415,
            326,
            416
          ],
          "Patches": [
            "xsa417.patch"
          ]
        }
      }
    },
    "4.15": {
      "Recipes": {
        "xen": {
          "StableRef": "816580afdd1730d4f85f64477a242a439af1cdf8",
          "Prereqs": [
            414,
            415,
            326,
            416
          ],
          "Patches": [
            "xsa417.patch"
          ]
        }
      }
    },
    "4.16": {
      "Recipes": {
        "xen": {
          "StableRef": "1bce7fb1f702da4f7a749c6f1457ecb20bf74fca",
          "Prereqs": [
            412,
            414,
            415,
            326,
            416
          ],
          "Patches": [
            "xsa417.patch"
          ]
        }
      }
    },
    "master": {
      "Recipes": {
        "xen": {
          "StableRef": "cc4747be8ba157a3b310921e9ee07fb8545aa206",
          "Prereqs": [
            412,
            414,
            415,
            326,
            416
          ],
          "Patches": [
            "xsa417.patch"
          ]
        }
      }
    }
  }
}From 67d5ecd609b8f12346eadb40e547cd7e01d825dc Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Tue, 13 Sep 2022 07:35:10 +0200
Subject: tools/xenstore: fix checking node permissions

Today chk_domain_generation() is being used to check whether a node
permission entry is still valid or whether it is referring to a domain
no longer existing. This is done by comparing the node's and the
domain's generation count.

In case no struct domain is existing for a checked domain, but the
domain itself is valid, chk_domain_generation() assumes it is being
called due to the first node created for a new domain and it will
return success.

This might be wrong in case the checked permission is related to an
old domain, which has just been replaced with a new domain using the
same domid.

Fix that by letting chk_domain_generation() fail in case a struct
domain isn't found. In order to cover the case of the first node for
a new domain try to allocate the needed struct domain explicitly when
processing the related SET_PERMS command. In case a referenced domain
isn't existing, flag the related permission to be ignored right away.

This is XSA-417 / CVE-2022-42320.

Reported-by: Juergen Gross <jgross@suse.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Julien Grall <jgrall@amazon.com>

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 66bbeaf6bfb0..a0c176fa203e 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1753,6 +1753,11 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
 		return errno;
 
+	if (domain_alloc_permrefs(&perms) < 0)
+		return ENOMEM;
+	if (perms.p[0].perms & XS_PERM_IGNORE)
+		return ENOENT;
+
 	/* First arg is node name. */
 	if (strstarts(in->buffer, "@")) {
 		if (set_perms_special(conn, in->buffer, &perms))
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index b9ff4ded8360..98b401fdec30 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -907,7 +907,6 @@ int domain_entry_inc(struct connection *conn, struct node *node)
  * count (used for testing whether a node permission is older than a domain).
  *
  * Return values:
- * -1: error
  *  0: domain has higher generation count (it is younger than a node with the
  *     given count), or domain isn't existing any longer
  *  1: domain is older than the node
@@ -915,20 +914,38 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 static int chk_domain_generation(unsigned int domid, uint64_t gen)
 {
 	struct domain *d;
-	xc_dominfo_t dominfo;
 
 	if (!xc_handle && domid == 0)
 		return 1;
 
 	d = find_domain_struct(domid);
-	if (d)
-		return (d->generation <= gen) ? 1 : 0;
 
-	if (!get_domain_info(domid, &dominfo))
-		return 0;
+	return (d && d->generation <= gen) ? 1 : 0;
+}
 
-	d = alloc_domain(NULL, domid);
-	return d ? 1 : -1;
+/*
+ * Allocate all missing struct domain referenced by a permission set.
+ * Any permission entries for not existing domains will be marked to be
+ * ignored.
+ */
+int domain_alloc_permrefs(struct node_perms *perms)
+{
+	unsigned int i, domid;
+	struct domain *d;
+	xc_dominfo_t dominfo;
+
+	for (i = 0; i < perms->num; i++) {
+		domid = perms->p[i].id;
+		d = find_domain_struct(domid);
+		if (!d) {
+			if (!get_domain_info(domid, &dominfo))
+				perms->p[i].perms |= XS_PERM_IGNORE;
+			else if (!alloc_domain(NULL, domid))
+				return ENOMEM;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -941,8 +958,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 	int ret;
 
 	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-	if (ret < 0)
-		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
 	if (!ret) {
@@ -959,8 +974,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 			continue;
 		ret = chk_domain_generation(node->perms.p[i].id,
 					    node->generation);
-		if (ret < 0)
-			return errno;
 		if (!ret)
 			node->perms.p[i].perms |= XS_PERM_IGNORE;
 	}
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 209442190911..7fe0a21d9e45 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -63,6 +63,7 @@ bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
 int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
 int domain_entry_inc(struct connection *conn, struct node *);