tools/ocaml/xenstored: Check for maxrequests before performing operations

Previously we'd perform the operation, record the updated tree in the
transaction record, then try to insert a watchop path and the reply packet.

If we exceeded max requests we would've returned EQUOTA, but still:
* have performed the operation on the transaction's tree
* have recorded the watchop, making this queue effectively unbounded

It is better if we check whether we'd have room to store the operation before
performing the transaction, and raise EQUOTA there.  Then the transaction
record won't grow.

This is part of XSA-326 / CVE-2022-42317.

Signed-off-by: Edwin Török <edvin.torok@citrix.com>
Acked-by: Christian Lindig <christian.lindig@citrix.com>
(cherry picked from commit 329f4d1a65)
This commit is contained in:
Edwin Török authored and Andrew Cooper committed 2022-11-01 15:25:15 +00:00
1 parent d71e4eca23
commit c084ee8e58
2 files changed
+15 -5

No files matched your search

+3 -1
View File
@@ -253,6 +253,7 @@ let input_handle_error ~cons ~doms ~fct ~con ~t ~req =
let reply_error e =
Packet.Error e in
try
Transaction.check_quota_exn ~perm:(Connection.get_perm con) t;
fct con t doms cons req.Packet.data
with
| Define.Invalid_path -> reply_error "EINVAL"
@@ -545,9 +546,10 @@ let process_packet ~store ~cons ~doms ~con ~req =
in
let response = try
Transaction.check_quota_exn ~perm:(Connection.get_perm con) t;
if tid <> Transaction.none then
(* Remember the request and response for this operation in case we need to replay the transaction *)
Transaction.add_operation ~perm:(Connection.get_perm con) t req response;
Transaction.add_operation t req response;
response
with Quota.Limit_reached ->
Packet.Error "EQUOTA"
+12 -4
View File
@@ -85,6 +85,7 @@ type t = {
oldroot: Store.Node.t;
mutable paths: (Xenbus.Xb.Op.operation * Store.Path.t) list;
mutable operations: (Packet.request * Packet.response) list;
mutable quota_reached: bool;
mutable read_lowpath: Store.Path.t option;
mutable write_lowpath: Store.Path.t option;
}
@@ -127,6 +128,7 @@ let make ?(internal=false) id store =
oldroot = Store.get_root store;
paths = [];
operations = [];
quota_reached = false;
read_lowpath = None;
write_lowpath = None;
} in
@@ -143,13 +145,19 @@ let get_root t = Store.get_root t.store
let is_read_only t = t.paths = []
let add_wop t ty path = t.paths <- (ty, path) :: t.paths
let add_operation ~perm t request response =
let get_operations t = List.rev t.operations
let check_quota_exn ~perm t =
if !Define.maxrequests >= 0
&& not (Perms.Connection.is_dom0 perm)
&& List.length t.operations >= !Define.maxrequests
then raise Quota.Limit_reached;
&& (t.quota_reached || List.length t.operations >= !Define.maxrequests)
then begin
t.quota_reached <- true;
raise Quota.Limit_reached;
end
let add_operation t request response =
t.operations <- (request, response) :: t.operations
let get_operations t = List.rev t.operations
let set_read_lowpath t path = t.read_lowpath <- get_lowest path t.read_lowpath
let set_write_lowpath t path = t.write_lowpath <- get_lowest path t.write_lowpath
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.