tools/xenstored: make conn_delete_all_transactions() idempotent

conn_delete_all_transactions() should be callable in any context,
resetting ALL transaction related data.

This includes number of active transactions and the transaction
pointer in struct connection.

So reset conn->trans to NULL in conn_delete_all_transactions() and
do the cleanup for each transaction in destroy_transaction().

This avoids triggering the assert() in conn_delete_all_transactions()
in case e.g. ignore_connection() was called while an operation inside
a transaction was performed, or XS_RESET_WATCHES was called in a
transaction.

This is XSA-484 / CVE-2026-23557.

Reported-by: Andrii Sultanov <andriy.sultanov@vates.tech>
Fixes: 1f9d04fb02 ("xenstored: allow guest to shutdown all its watches/transactions")
Signed-off-by: Juergen Gross <jgross@suse.com>
This commit is contained in:
Juergen Gross authored and Andrew Cooper committed 2026-04-28 13:41:32 +01:00
1 parent af9e77f5ff
commit e88031d1fe
1 file changed
+9 -11
+9 -11
View File
@@ -434,17 +434,23 @@ static int finalize_transaction(struct connection *conn,
static int destroy_transaction(void *_transaction)
{
struct transaction *trans = _transaction;
struct connection *conn = trans->conn;
struct accessed_node *i;
wrl_ntransactions--;
trace_destroy(trans, "transaction");
while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
if (i->ta_node)
db_delete(trans->conn, i->trans_name, NULL);
db_delete(conn, i->trans_name, NULL);
list_del(&i->list);
talloc_free(i);
}
list_del(&trans->list);
domain_transaction_dec(conn);
if (list_empty(&conn->transaction_list))
conn->ta_start_time = 0;
return 0;
}
@@ -525,10 +531,6 @@ int do_transaction_end(const void *ctx, struct connection *conn,
return ENOENT;
conn->transaction = NULL;
list_del(&trans->list);
domain_transaction_dec(conn);
if (list_empty(&conn->transaction_list))
conn->ta_start_time = 0;
chk_quota = trans->node_created && domain_is_unprivileged(conn);
@@ -574,14 +576,10 @@ void conn_delete_all_transactions(struct connection *conn)
struct transaction *trans;
while ((trans = list_top(&conn->transaction_list,
struct transaction, list))) {
list_del(&trans->list);
struct transaction, list)))
talloc_free(trans);
}
assert(conn->transaction == NULL);
conn->ta_start_time = 0;
conn->transaction = NULL;
}
int check_transactions(struct hashtable *hash)
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.