tools/oxenstored: Trim txhistory on xenbus reconnect
authorEdwin Török <edvin.torok@citrix.com>
Fri, 8 Jan 2021 11:57:37 +0000 (11:57 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 22 Jan 2021 18:01:34 +0000 (18:01 +0000)
There is a global history, containing transactions from the past 0.05s, which
get trimmed whenever any transaction commits or aborts.  Destroying a domain
will cause xenopsd to perform some transactions deleting the tree, so that is
fine.  But I think that a domain can abuse the xenbus reconnect facility to
cause a large history to be recorded - provided that noone does any
transactions on the system inbetween, which may be difficult to achieve given
squeezed's constant pinging.

The theoretical situation is like this:
- a domain starts a transaction, creates as large a tree as it can, commits
  it. Then repeatedly:
    - start a transaction, do nothing with it, start a transaction, delete
      part of the large tree, write some new unique data there, don't commit
    - cause a xenbus reconnect (I think this can be done by writing something
      to the ring). This causes all transactions/watches for the connection to
      be cleared, but NOT the history, there were no commits, so nobody
      trimmed the history, i.e. it the history can contain transactions from
      more than just 0.05s
    - loop back and start more transactions, you can keep this up indefinitely
      without hitting quotas

Now there is a periodic History.trim running every 0.05s, so I don't think you
can do much damage with it.  But lets be safe an trim the transaction history
anyway on reconnect.

Signed-off-by: Edwin Török <edvin.torok@citrix.com>
Acked-by: Christian Lindig <christian.lindig@citrix.com>
tools/ocaml/xenstored/connection.ml
tools/ocaml/xenstored/history.ml
tools/ocaml/xenstored/process.ml

index a36ec4a821d4bcb92d7c6bb12caef4af7a8a1e93..684f7a3861758aeffa9a8a4422b81f6e99b67b1d 100644 (file)
@@ -47,7 +47,7 @@ let mark_as_bad con =
 
 let initial_next_tid = 1
 
-let reconnect con =
+let do_reconnect con =
        Xenbus.Xb.reconnect con.xb;
        (* dom is the same *)
        Hashtbl.clear con.transactions;
index f39565bff5a81e2738511356cbe67431d6bd6f42..3899353da8359d2f4d8672acacd93257564970e6 100644 (file)
@@ -53,6 +53,10 @@ let end_transaction txn con tid commit =
        trim ~txn ();
        success
 
+let reconnect con =
+       trim ();
+       Connection.do_reconnect con
+
 let push (x: history_record) =
        let dom = x.con.Connection.dom in
        match dom with
index 584c03b3324eecec2e5a2e27c813d5c0c1bdaf1c..27790d4a5c41280e38b77b4e6348c3d9fe906a76 100644 (file)
@@ -702,7 +702,7 @@ let do_input store cons doms con =
                        Connection.do_input con
                with Xenbus.Xb.Reconnect ->
                        info "%s requests a reconnect" (Connection.get_domstr con);
-                       Connection.reconnect con;
+                       History.reconnect con;
                        info "%s reconnection complete" (Connection.get_domstr con);
                        false
                | Failure exp ->
@@ -741,7 +741,7 @@ let do_output _store _cons _doms con =
                        ignore (Connection.do_output con)
                with Xenbus.Xb.Reconnect ->
                        info "%s requests a reconnect" (Connection.get_domstr con);
-                       Connection.reconnect con;
+                       History.reconnect con;
                        info "%s reconnection complete" (Connection.get_domstr con)
        )