[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen stable-4.13] tools/xenstore: allow removing child of a node exceeding quota



commit 4959626e926ce2e6de731135b1f567433edcd992
Author:     Juergen Gross <jgross@xxxxxxxx>
AuthorDate: Thu Jun 11 16:12:37 2020 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Dec 15 14:18:22 2020 +0100

    tools/xenstore: allow removing child of a node exceeding quota
    
    An unprivileged user of Xenstore is not allowed to write nodes with a
    size exceeding a global quota, while privileged users like dom0 are
    allowed to write such nodes. The size of a node is the needed space
    to store all node specific data, this includes the names of all
    children of the node.
    
    When deleting a node its parent has to be modified by removing the
    name of the to be deleted child from it.
    
    This results in the strange situation that an unprivileged owner of a
    node might not succeed in deleting that node in case its parent is
    exceeding the quota of that unprivileged user (it might have been
    written by dom0), as the user is not allowed to write the updated
    parent node.
    
    Fix that by not checking the quota when writing a node for the
    purpose of removing a child's name only.
    
    The same applies to transaction handling: a node being read during a
    transaction is written to the transaction specific area and it should
    not be tested for exceeding the quota, as it might not be owned by
    the reader and presumably the original write would have failed if the
    node is owned by the reader.
    
    This is part of XSA-115.
    
    Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
    Reviewed-by: Julien Grall <jgrall@xxxxxxxxxx>
    Reviewed-by: Paul Durrant <paul@xxxxxxx>
---
 tools/xenstore/xenstored_core.c        | 20 +++++++++++---------
 tools/xenstore/xenstored_core.h        |  3 ++-
 tools/xenstore/xenstored_transaction.c |  2 +-
 3 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 97ceabf964..b43e1018ba 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -417,7 +417,8 @@ static struct node *read_node(struct connection *conn, 
const void *ctx,
        return node;
 }
 
-int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node)
+int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
+                  bool no_quota_check)
 {
        TDB_DATA data;
        void *p;
@@ -427,7 +428,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, 
struct node *node)
                + node->num_perms*sizeof(node->perms[0])
                + node->datalen + node->childlen;
 
-       if (domain_is_unprivileged(conn) &&
+       if (!no_quota_check && domain_is_unprivileged(conn) &&
            data.dsize >= quota_max_entry_size) {
                errno = ENOSPC;
                return errno;
@@ -455,14 +456,15 @@ int write_node_raw(struct connection *conn, TDB_DATA 
*key, struct node *node)
        return 0;
 }
 
-static int write_node(struct connection *conn, struct node *node)
+static int write_node(struct connection *conn, struct node *node,
+                     bool no_quota_check)
 {
        TDB_DATA key;
 
        if (access_node(conn, node, NODE_ACCESS_WRITE, &key))
                return errno;
 
-       return write_node_raw(conn, &key, node);
+       return write_node_raw(conn, &key, node, no_quota_check);
 }
 
 static enum xs_perm_type perm_for_conn(struct connection *conn,
@@ -999,7 +1001,7 @@ static struct node *create_node(struct connection *conn, 
const void *ctx,
        /* We write out the nodes down, setting destructor in case
         * something goes wrong. */
        for (i = node; i; i = i->parent) {
-               if (write_node(conn, i)) {
+               if (write_node(conn, i, false)) {
                        domain_entry_dec(conn, i);
                        return NULL;
                }
@@ -1039,7 +1041,7 @@ static int do_write(struct connection *conn, struct 
buffered_data *in)
        } else {
                node->data = in->buffer + offset;
                node->datalen = datalen;
-               if (write_node(conn, node))
+               if (write_node(conn, node, false))
                        return errno;
        }
 
@@ -1115,7 +1117,7 @@ static int remove_child_entry(struct connection *conn, 
struct node *node,
        size_t childlen = strlen(node->children + offset);
        memdel(node->children, offset, childlen + 1, node->childlen);
        node->childlen -= childlen + 1;
-       return write_node(conn, node);
+       return write_node(conn, node, true);
 }
 
 
@@ -1254,7 +1256,7 @@ static int do_set_perms(struct connection *conn, struct 
buffered_data *in)
        node->num_perms = num;
        domain_entry_inc(conn, node);
 
-       if (write_node(conn, node))
+       if (write_node(conn, node, false))
                return errno;
 
        fire_watches(conn, in, name, false);
@@ -1514,7 +1516,7 @@ static void manual_node(const char *name, const char 
*child)
        if (child)
                node->childlen = strlen(child) + 1;
 
-       if (write_node(NULL, node))
+       if (write_node(NULL, node, false))
                barf_perror("Could not create initial node %s", name);
        talloc_free(node);
 }
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index c4c32bc88f..29d638fbc5 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -149,7 +149,8 @@ void send_ack(struct connection *conn, enum 
xsd_sockmsg_type type);
 char *canonicalize(struct connection *conn, const void *ctx, const char *node);
 
 /* Write a node to the tdb data base. */
-int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node);
+int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
+                  bool no_quota_check);
 
 /* Get this node, checking we have permissions. */
 struct node *get_node(struct connection *conn,
diff --git a/tools/xenstore/xenstored_transaction.c 
b/tools/xenstore/xenstored_transaction.c
index 2824f7b359..e878975734 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -276,7 +276,7 @@ int access_node(struct connection *conn, struct node *node,
                        i->check_gen = true;
                        if (node->generation != NO_GENERATION) {
                                set_tdb_key(trans_name, &local_key);
-                               ret = write_node_raw(conn, &local_key, node);
+                               ret = write_node_raw(conn, &local_key, node, 
true);
                                if (ret)
                                        goto err;
                                i->ta_node = true;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.