summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '0098-tools-xenstore-add-memory-accounting-for-nodes.patch')
-rw-r--r--0098-tools-xenstore-add-memory-accounting-for-nodes.patch342
1 files changed, 0 insertions, 342 deletions
diff --git a/0098-tools-xenstore-add-memory-accounting-for-nodes.patch b/0098-tools-xenstore-add-memory-accounting-for-nodes.patch
deleted file mode 100644
index f2f8e4f..0000000
--- a/0098-tools-xenstore-add-memory-accounting-for-nodes.patch
+++ /dev/null
@@ -1,342 +0,0 @@
-From 32efe29a00efab2896cc973e966a35ecad556495 Mon Sep 17 00:00:00 2001
-From: Juergen Gross <jgross@suse.com>
-Date: Tue, 13 Sep 2022 07:35:10 +0200
-Subject: [PATCH 098/126] tools/xenstore: add memory accounting for nodes
-
-Add the memory accounting for Xenstore nodes. In order to make this
-not too complicated allow for some sloppiness when writing nodes. Any
-hard quota violation will result in no further requests to be accepted.
-
-This is part of XSA-326 / CVE-2022-42315.
-
-Signed-off-by: Juergen Gross <jgross@suse.com>
-Reviewed-by: Julien Grall <jgrall@amazon.com>
-(cherry picked from commit 00e9e32d022be1afc144b75acdaeba8393e63315)
----
- tools/xenstore/xenstored_core.c | 140 ++++++++++++++++++++++---
- tools/xenstore/xenstored_core.h | 12 +++
- tools/xenstore/xenstored_transaction.c | 16 ++-
- 3 files changed, 151 insertions(+), 17 deletions(-)
-
-diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
-index b1a4575929bd..f27d5c0101bc 100644
---- a/tools/xenstore/xenstored_core.c
-+++ b/tools/xenstore/xenstored_core.c
-@@ -556,6 +556,117 @@ void set_tdb_key(const char *name, TDB_DATA *key)
- key->dsize = strlen(name);
- }
-
-+static void get_acc_data(TDB_DATA *key, struct node_account_data *acc)
-+{
-+ TDB_DATA old_data;
-+ struct xs_tdb_record_hdr *hdr;
-+
-+ if (acc->memory < 0) {
-+ old_data = tdb_fetch(tdb_ctx, *key);
-+ /* No check for error, as the node might not exist. */
-+ if (old_data.dptr == NULL) {
-+ acc->memory = 0;
-+ } else {
-+ hdr = (void *)old_data.dptr;
-+ acc->memory = old_data.dsize;
-+ acc->domid = hdr->perms[0].id;
-+ }
-+ talloc_free(old_data.dptr);
-+ }
-+}
-+
-+/*
-+ * Per-transaction nodes need to be accounted for the transaction owner.
-+ * Those nodes are stored in the data base with the transaction generation
-+ * count prepended (e.g. 123/local/domain/...). So testing for the node's
-+ * key not to start with "/" is sufficient.
-+ */
-+static unsigned int get_acc_domid(struct connection *conn, TDB_DATA *key,
-+ unsigned int domid)
-+{
-+ return (!conn || key->dptr[0] == '/') ? domid : conn->id;
-+}
-+
-+int do_tdb_write(struct connection *conn, TDB_DATA *key, TDB_DATA *data,
-+ struct node_account_data *acc, bool no_quota_check)
-+{
-+ struct xs_tdb_record_hdr *hdr = (void *)data->dptr;
-+ struct node_account_data old_acc = {};
-+ unsigned int old_domid, new_domid;
-+ int ret;
-+
-+ if (!acc)
-+ old_acc.memory = -1;
-+ else
-+ old_acc = *acc;
-+
-+ get_acc_data(key, &old_acc);
-+ old_domid = get_acc_domid(conn, key, old_acc.domid);
-+ new_domid = get_acc_domid(conn, key, hdr->perms[0].id);
-+
-+ /*
-+ * Don't check for ENOENT, as we want to be able to switch orphaned
-+ * nodes to new owners.
-+ */
-+ if (old_acc.memory)
-+ domain_memory_add_nochk(old_domid,
-+ -old_acc.memory - key->dsize);
-+ ret = domain_memory_add(new_domid, data->dsize + key->dsize,
-+ no_quota_check);
-+ if (ret) {
-+ /* Error path, so no quota check. */
-+ if (old_acc.memory)
-+ domain_memory_add_nochk(old_domid,
-+ old_acc.memory + key->dsize);
-+ return ret;
-+ }
-+
-+ /* TDB should set errno, but doesn't even set ecode AFAICT. */
-+ if (tdb_store(tdb_ctx, *key, *data, TDB_REPLACE) != 0) {
-+ domain_memory_add_nochk(new_domid, -data->dsize - key->dsize);
-+ /* Error path, so no quota check. */
-+ if (old_acc.memory)
-+ domain_memory_add_nochk(old_domid,
-+ old_acc.memory + key->dsize);
-+ errno = EIO;
-+ return errno;
-+ }
-+
-+ if (acc) {
-+ /* Don't use new_domid, as it might be a transaction node. */
-+ acc->domid = hdr->perms[0].id;
-+ acc->memory = data->dsize;
-+ }
-+
-+ return 0;
-+}
-+
-+int do_tdb_delete(struct connection *conn, TDB_DATA *key,
-+ struct node_account_data *acc)
-+{
-+ struct node_account_data tmp_acc;
-+ unsigned int domid;
-+
-+ if (!acc) {
-+ acc = &tmp_acc;
-+ acc->memory = -1;
-+ }
-+
-+ get_acc_data(key, acc);
-+
-+ if (tdb_delete(tdb_ctx, *key)) {
-+ errno = EIO;
-+ return errno;
-+ }
-+
-+ if (acc->memory) {
-+ domid = get_acc_domid(conn, key, acc->domid);
-+ domain_memory_add_nochk(domid, -acc->memory - key->dsize);
-+ }
-+
-+ return 0;
-+}
-+
- /*
- * If it fails, returns NULL and sets errno.
- * Temporary memory allocations will be done with ctx.
-@@ -609,9 +720,15 @@ struct node *read_node(struct connection *conn, const void *ctx,
-
- /* Permissions are struct xs_permissions. */
- node->perms.p = hdr->perms;
-+ node->acc.domid = node->perms.p[0].id;
-+ node->acc.memory = data.dsize;
- if (domain_adjust_node_perms(conn, node))
- goto error;
-
-+ /* If owner is gone reset currently accounted memory size. */
-+ if (node->acc.domid != node->perms.p[0].id)
-+ node->acc.memory = 0;
-+
- /* Data is binary blob (usually ascii, no nul). */
- node->data = node->perms.p + hdr->num_perms;
- /* Children is strings, nul separated. */
-@@ -680,12 +797,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
- p += node->datalen;
- memcpy(p, node->children, node->childlen);
-
-- /* TDB should set errno, but doesn't even set ecode AFAICT. */
-- if (tdb_store(tdb_ctx, *key, data, TDB_REPLACE) != 0) {
-- corrupt(conn, "Write of %s failed", key->dptr);
-- errno = EIO;
-- return errno;
-- }
-+ if (do_tdb_write(conn, key, &data, &node->acc, no_quota_check))
-+ return EIO;
-+
- return 0;
- }
-
-@@ -1188,7 +1302,7 @@ static void delete_node_single(struct connection *conn, struct node *node)
- if (access_node(conn, node, NODE_ACCESS_DELETE, &key))
- return;
-
-- if (tdb_delete(tdb_ctx, key) != 0) {
-+ if (do_tdb_delete(conn, &key, &node->acc) != 0) {
- corrupt(conn, "Could not delete '%s'", node->name);
- return;
- }
-@@ -1261,6 +1375,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx,
- /* No children, no data */
- node->children = node->data = NULL;
- node->childlen = node->datalen = 0;
-+ node->acc.memory = 0;
- node->parent = parent;
- return node;
-
-@@ -1269,17 +1384,17 @@ nomem:
- return NULL;
- }
-
--static void destroy_node_rm(struct node *node)
-+static void destroy_node_rm(struct connection *conn, struct node *node)
- {
- if (streq(node->name, "/"))
- corrupt(NULL, "Destroying root node!");
-
-- tdb_delete(tdb_ctx, node->key);
-+ do_tdb_delete(conn, &node->key, &node->acc);
- }
-
- static int destroy_node(struct connection *conn, struct node *node)
- {
-- destroy_node_rm(node);
-+ destroy_node_rm(conn, node);
- domain_entry_dec(conn, node);
-
- /*
-@@ -1331,7 +1446,7 @@ static struct node *create_node(struct connection *conn, const void *ctx,
- /* Account for new node */
- if (i->parent) {
- if (domain_entry_inc(conn, i)) {
-- destroy_node_rm(i);
-+ destroy_node_rm(conn, i);
- return NULL;
- }
- }
-@@ -2192,7 +2307,7 @@ static int clean_store_(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA val,
- if (!hashtable_search(reachable, name)) {
- log("clean_store: '%s' is orphaned!", name);
- if (recovery) {
-- tdb_delete(tdb, key);
-+ do_tdb_delete(NULL, &key, NULL);
- }
- }
-
-@@ -3030,6 +3145,7 @@ void read_state_node(const void *ctx, const void *state)
- if (!node)
- barf("allocation error restoring node");
-
-+ node->acc.memory = 0;
- node->name = name;
- node->generation = ++generation;
- node->datalen = sn->data_len;
-diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
-index 2fb37dbfe847..5c1b574bffe6 100644
---- a/tools/xenstore/xenstored_core.h
-+++ b/tools/xenstore/xenstored_core.h
-@@ -169,6 +169,11 @@ struct node_perms {
- struct xs_permissions *p;
- };
-
-+struct node_account_data {
-+ unsigned int domid;
-+ int memory; /* -1 if unknown */
-+};
-+
- struct node {
- const char *name;
- /* Key used to update TDB */
-@@ -191,6 +196,9 @@ struct node {
- /* Children, each nul-terminated. */
- unsigned int childlen;
- char *children;
-+
-+ /* Allocation information for node currently in store. */
-+ struct node_account_data acc;
- };
-
- /* Return the only argument in the input. */
-@@ -300,6 +308,10 @@ extern xengnttab_handle **xgt_handle;
- int remember_string(struct hashtable *hash, const char *str);
-
- void set_tdb_key(const char *name, TDB_DATA *key);
-+int do_tdb_write(struct connection *conn, TDB_DATA *key, TDB_DATA *data,
-+ struct node_account_data *acc, bool no_quota_check);
-+int do_tdb_delete(struct connection *conn, TDB_DATA *key,
-+ struct node_account_data *acc);
-
- void conn_free_buffered_data(struct connection *conn);
-
-diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
-index 7bd41eb475e3..ace9a11d77bb 100644
---- a/tools/xenstore/xenstored_transaction.c
-+++ b/tools/xenstore/xenstored_transaction.c
-@@ -153,6 +153,9 @@ struct transaction
- /* List of all transactions active on this connection. */
- struct list_head list;
-
-+ /* Connection this transaction is associated with. */
-+ struct connection *conn;
-+
- /* Connection-local identifier for this transaction. */
- uint32_t id;
-
-@@ -286,6 +289,8 @@ int access_node(struct connection *conn, struct node *node,
-
- introduce = true;
- i->ta_node = false;
-+ /* acc.memory < 0 means "unknown, get size from TDB". */
-+ node->acc.memory = -1;
-
- /*
- * Additional transaction-specific node for read type. We only
-@@ -410,11 +415,11 @@ static int finalize_transaction(struct connection *conn,
- goto err;
- hdr = (void *)data.dptr;
- hdr->generation = ++generation;
-- ret = tdb_store(tdb_ctx, key, data,
-- TDB_REPLACE);
-+ ret = do_tdb_write(conn, &key, &data, NULL,
-+ true);
- talloc_free(data.dptr);
- } else {
-- ret = tdb_delete(tdb_ctx, key);
-+ ret = do_tdb_delete(conn, &key, NULL);
- }
- if (ret)
- goto err;
-@@ -425,7 +430,7 @@ static int finalize_transaction(struct connection *conn,
- }
- }
-
-- if (i->ta_node && tdb_delete(tdb_ctx, ta_key))
-+ if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL))
- goto err;
- list_del(&i->list);
- talloc_free(i);
-@@ -453,7 +458,7 @@ static int destroy_transaction(void *_transaction)
- i->node);
- if (trans_name) {
- set_tdb_key(trans_name, &key);
-- tdb_delete(tdb_ctx, key);
-+ do_tdb_delete(trans->conn, &key, NULL);
- }
- }
- list_del(&i->list);
-@@ -497,6 +502,7 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
-
- INIT_LIST_HEAD(&trans->accessed);
- INIT_LIST_HEAD(&trans->changed_domains);
-+ trans->conn = conn;
- trans->fail = false;
- trans->generation = ++generation;
-
---
-2.37.4
-