[prev in list] [next in list] [prev in thread] [next in thread] 

List:       oss-security
Subject:    [oss-security] Xen Security Advisory 354 v4 (CVE-2020-29487) - XAPI: guest-triggered excessive memor
From:       Xen.org security team <security () xen ! org>
Date:       2020-12-15 12:20:26
Message-ID: E1kp9Ja-00079y-DC () xenbits ! xenproject ! org
[Download RAW message or body]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

            Xen Security Advisory CVE-2020-29487 / XSA-354
                               version 4

             XAPI: guest-triggered excessive memory usage

UPDATES IN VERSION 4
====================

Public release.

ISSUE DESCRIPTION
=================

Certain xenstore keys provide feedback from the guest, and are therefore
watched by toolstack.  Specifically, keys are watched by xenopsd, and
data are forward via RPC through message-switch to xapi.

The watching logic in xenopsd sends one RPC update containing all data,
any time any single xenstore key is updated, and therefore has O(N^2)
time complexity.  Furthermore, message-switch retains recent (currently
128) RPC messages for diagnostic purposes, yielding O(M*N) space
complexity.

The quantity of memory a single guest can monopolise is bounded by
xenstored quota, but the quota is fairly large.  It is believed to be in
excess of 1G per malicious guest.

In practice this manifests as a host denial of service, either through
message-switch thrashing against swap, or OOM'ing entirely, depending on
dom0's configuration.

This series introduces quotas in xenopsd to limit the quantity of keys
which result in RPC traffic.

IMPACT
======

A buggy or malicious guest can cause unreasonable memory usage in dom0,
resulting in a host denial of service.

VULNERABLE SYSTEMS
==================

All versions of XAPI are vulnerable.

Systems which are not using the XAPI toolstack are not vulnerable.

MITIGATION
==========

There are no mitigations available.

CREDITS
=======

This issue was discovered by Edwin Török of Citrix.

RESOLUTION
==========

Applying the appropriate attached patch resolves this issue.

Note that patches for released versions are generally prepared to
apply to the stable branches, and may not apply cleanly to the most
recent release tarball.  Downstreams are encouraged to update to the
tip of the stable branch before applying these patches.

xsa354-*.patch         xenopsd master

$ sha256sum xsa354*
66d29c38ce4fa6c77a4853a0f0345f3bf1fcbe11703090e1dbfa83257564de42  \
xsa354-1-ls_lR-factor-out-dir-concatenation.patch \
0686465119b4442d839d59c66c41d02ce6b4cfa9c82234e0aefcaffbb7985ee4  \
xsa354-2-ls_lR-refactor-use-fold.patch \
fb60812f1230526f9c3be77d4f0c8c08903b21aa5c449056dc16b1181720b3cb  \
xsa354-3-ls_lR-separate-recursion-into-separate-funct.patch \
41f221007abd89c8d24dacb7b0ff96109427c1c84eae75b7245bb287a0938d81  \
xsa354-4-ls_lR-add-quota.patch fcd4abddf18bc5b875ec28213f3138f1de395e91076b5b1a828353bc8b19d8ed \
xsa354-5-ls_lR-limit-depth.patch \
1ff82640a446407492904b50b05fc903a70d570620cd20a21493c9240b38f8be  \
xsa354-6-exclude-attr-os-hotfixes-from-ls_lR.patch \
b1b2f96b93d41201ddfdb093660f06f8bce5461a715cfeb7110f0194b74c93cb  \
xsa354-7-read-important-xenstore-entries-first.patch \
6908e957c299fe57dcd5c5c93162d135326221f1e66ac4b43b771ebd63bae35d  \
xsa354-8-refactor-attr-os-hotfixes-exclusion.patch $

DEPLOYMENT DURING EMBARGO
=========================

Deployment of the patches and/or mitigations described above (or
others which are substantially similar) is permitted during the
embargo, even on public-facing systems with untrusted guest users and
administrators.

But: Distribution of updated software is prohibited (except to other
members of the predisclosure list).

Predisclosure list members who wish to deploy significantly different
patches and/or mitigations, please contact the Xen Project Security
Team.


(Note: this during-embargo deployment notice is retained in
post-embargo publicly released Xen Project advisories, even though it
is then no longer applicable.  This is to enable the community to have
oversight of the Xen Project Security Team's decisionmaking.)

For more information about permissible uses of embargoed information,
consult the Xen Project community's agreed Security Policy:
  http://www.xenproject.org/security-policy.html
-----BEGIN PGP SIGNATURE-----

iQFABAEBCAAqFiEEI+MiLBRfRHX6gGCng/4UyVfoK9kFAl/YqeAMHHBncEB4ZW4u
b3JnAAoJEIP+FMlX6CvZA0MIAK9VhZjA0/adgq4TY2DXFjIZKg6Q9ZE9cBZcgv4l
XhGpAwxeYKU76KFEf1si3KCGV7xzHG0tnwkEgfpeldnGCwsgSkJPRNFvgA/7iuW0
3hCAdRioSU9Rm3h2gQdIDBAppvD0NhkkjQU/XcrB7qeOjfYrdvH5gS+NSRN/z50V
g02kUrWypShC0+lvgkJ0zXfl0CAQSs27BMd2vlj5BuOP573IrbJh6NHuRMF9Dm9J
48ny910Ctws5FSbe25ZgZHERZnwDnwe/oGP1ws12wZbU8ToP5t7tHnSQGNgwXPWT
Xpoecr5Iqek2CUHPEd8KKKS4B5frJHq+Xp8CAfnX8KT8VH8=
=y19v
-----END PGP SIGNATURE-----


["xsa354-1-ls_lR-factor-out-dir-concatenation.patch" (application/octet-stream)]

From 81f7bfe89cb1101fad67e5db7779809111359a6e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Edwin Török?= <edvin.torok@citrix.com>
Date: Wed, 4 Nov 2020 19:39:43 +0000
Subject: XSA-354: ls_lR: factor out dir concatenation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Edwin Török <edvin.torok@citrix.com>
Acked-by: Christian Lindig <christian.lindig@citrix.com>

diff --git a/xc/xenops_server_xen.ml b/xc/xenops_server_xen.ml
index 69404de6..008e8dda 100644
--- a/xc/xenops_server_xen.ml
+++ b/xc/xenops_server_xen.ml
@@ -2592,12 +2592,11 @@ module VM = struct
               with Xs_protocol.Enoent _ -> ""
             in
             let rec ls_lR root dir -              let this -                try [(dir, \
                xs.Xs.read (root ^ "/" ^ dir))] with _ -> []
-              in
+              let entry = root ^ "/" ^ dir in
+              let this = try [(dir, xs.Xs.read entry)] with _ -> [] in
               let subdirs                  try
-                  xs.Xs.directory (root ^ "/" ^ dir)
+                  xs.Xs.directory entry
                   |> List.filter (fun x -> x <> "")
                   |> map_tr (fun x -> dir ^ "/" ^ x)
                 with _ -> []


["xsa354-2-ls_lR-refactor-use-fold.patch" (application/octet-stream)]

From 193a03d759b320ff4078352087a576ed138c6fc6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Edwin Török?= <edvin.torok@citrix.com>
Date: Wed, 4 Nov 2020 19:46:31 +0000
Subject: XSA-354: ls_lR: refactor, use fold
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Edwin Török <edvin.torok@citrix.com>
Acked-by: Christian Lindig <christian.lindig@citrix.com>

diff --git a/xc/xenops_server_xen.ml b/xc/xenops_server_xen.ml
index 008e8dda..912e97fa 100644
--- a/xc/xenops_server_xen.ml
+++ b/xc/xenops_server_xen.ml
@@ -2591,9 +2591,9 @@ module VM = struct
                      (Uuidm.to_string uuid))
               with Xs_protocol.Enoent _ -> ""
             in
-            let rec ls_lR root dir +            let rec ls_lR root acc dir                let \
                entry = root ^ "/" ^ dir in
-              let this = try [(dir, xs.Xs.read entry)] with _ -> [] in
+              let acc = try (dir, xs.Xs.read entry) :: acc with _ -> acc in
               let subdirs                  try
                   xs.Xs.directory entry
@@ -2601,22 +2601,22 @@ module VM = struct
                   |> map_tr (fun x -> dir ^ "/" ^ x)
                 with _ -> []
               in
-              this @ List.concat (map_tr (ls_lR root) subdirs)
+              List.fold_left (ls_lR root) acc subdirs
             in
             let guest_agent                [
                 "drivers"; "attr"; "data"; "control"; "feature"; "xenserver/attr"
               ]
-              |> map_tr
+              |> List.fold_left
                    (ls_lR (Printf.sprintf "/local/domain/%d" di.Xenctrl.domid))
-              |> List.concat
+                   []
               |> map_tr (fun (k, v) -> (k, Xenops_utils.utf8_recode v))
             in
             let xsdata_state                Domain.allowed_xsdata_prefixes
-              |> map_tr
+              |> List.fold_left
                    (ls_lR (Printf.sprintf "/local/domain/%d" di.Xenctrl.domid))
-              |> List.concat
+                   []
             in
             let shadow_multiplier_target                if not di.Xenctrl.hvm_guest then


["xsa354-3-ls_lR-separate-recursion-into-separate-funct.patch" (application/octet-stream)]

From 94e4de6fd3413827dffec06d5a74b3e673a7cc2c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Edwin Török?= <edvin.torok@citrix.com>
Date: Wed, 4 Nov 2020 19:52:20 +0000
Subject: XSA-354: ls_lR: separate recursion into separate function
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This will make it easier to add quota checks.

Signed-off-by: Edwin Török <edvin.torok@citrix.com>
Acked-by: Christian Lindig <christian.lindig@citrix.com>

diff --git a/xc/xenops_server_xen.ml b/xc/xenops_server_xen.ml
index 912e97fa..84c59f13 100644
--- a/xc/xenops_server_xen.ml
+++ b/xc/xenops_server_xen.ml
@@ -2591,9 +2591,11 @@ module VM = struct
                      (Uuidm.to_string uuid))
               with Xs_protocol.Enoent _ -> ""
             in
-            let rec ls_lR root acc dir +            let ls_l root dir                let entry \
                = root ^ "/" ^ dir in
-              let acc = try (dir, xs.Xs.read entry) :: acc with _ -> acc in
+              let value_opt +                try Some (dir, xs.Xs.read entry) with _ -> None
+              in
               let subdirs                  try
                   xs.Xs.directory entry
@@ -2601,6 +2603,13 @@ module VM = struct
                   |> map_tr (fun x -> dir ^ "/" ^ x)
                 with _ -> []
               in
+              (value_opt, subdirs)
+            in
+            let rec ls_lR root acc dir +              let value_opt, subdirs = ls_l root dir \
in +              let acc +                match value_opt with Some v -> v :: acc | None -> \
acc +              in
               List.fold_left (ls_lR root) acc subdirs
             in
             let guest_agent 


["xsa354-4-ls_lR-add-quota.patch" (application/octet-stream)]

From 4967b9eff36f637f9e608559b15e12553b0b9322 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Edwin Török?= <edvin.torok@citrix.com>
Date: Wed, 4 Nov 2020 20:00:46 +0000
Subject: XSA-354: ls_lR: add quota
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

xenopsd watches certain sub-trees in the guest:
vm-data, FIST, drivers, attr, data, control, feature, xenserver/attr

vm-data is replicated as is into the XAPI database, which raises a DoS
concern: each key update is amplified in DB and message-switch traffic:
the entire VM objects needs to be read and written back, which results
in O(N^2) operation if we insert N keys.

VMs do have xenstore quotas, but even when they work they are fairly
large (8192 keys). It is not easy to reduce that quota (calculating
number of keys legitimately needed for 255 disks, 8 NICs, 32 vCPUs,
etc.) results in ~7000 keys already.

However vm-data is not meant as a general purpose data store, and
although it probably shouldn't have existed in the first place, we can't
change that for LCM releases. Lets at least add a small quota on it,
such that N^2 isn't too big.

With this change xenopsd doesn't run out of memory anymore (as long as
oxenstored properly enforces quota).  Now a VM should only be able to
store ~2.3MiB, instead of ~144MiB which is a significant reduction.

We should consider introducing a limit in bytes, although that would be
more complicated because the XML serialization can amplify the size
(e.g. " gets turned into &quot;) and is a XAPI implementation detail.

Signed-off-by: Edwin Török <edvin.torok@citrix.com>
Acked-by: Christian Lindig <christian.lindig@citrix.com>

diff --git a/lib/xenopsd.ml b/lib/xenopsd.ml
index cb418516..94c55930 100644
--- a/lib/xenopsd.ml
+++ b/lib/xenopsd.ml
@@ -66,6 +66,9 @@ let numa_placement = ref false
 (* This is for debugging only *)
 let numa_placement_strict = ref false

+(* O(N^2) operations, until we get a xenstore cache, so use a small number here *)
+let vm_xenstore_ls_lR_quota = ref 128
+
 let options    [
     ( "queue"
@@ -169,6 +172,10 @@ let options      , (fun () -> string_of_bool !pci_quarantine)
     , "True if IOMMU contexts of PCI devices are needed to be placed in \
        quarantine" )
+  ; ( "vm-xenstore-ls-lR-quota"
+    , Arg.Set_int vm_xenstore_ls_lR_quota
+    , (fun () -> string_of_int !vm_xenstore_ls_lR_quota)
+    , "Maximum entries in VM xenstore trees watched by xenopsd" )
   ]

 let path () = Filename.concat !sockets_path "xenopsd"
diff --git a/xc/xenops_server_xen.ml b/xc/xenops_server_xen.ml
index 84c59f13..31a22186 100644
--- a/xc/xenops_server_xen.ml
+++ b/xc/xenops_server_xen.ml
@@ -2591,42 +2591,71 @@ module VM = struct
                      (Uuidm.to_string uuid))
               with Xs_protocol.Enoent _ -> ""
             in
-            let ls_l root dir +            let ls_l ~depth root dir                let entry = root ^ "/" ^ dir in
               let value_opt                  try Some (dir, xs.Xs.read entry) with _ -> None
               in
               let subdirs -                try
-                  xs.Xs.directory entry
-                  |> List.filter (fun x -> x <> "")
-                  |> map_tr (fun x -> dir ^ "/" ^ x)
-                with _ -> []
+                if depth < 0 then
+                  []
+                (* depth limit reached, at a depth of 0 we still read entries/values, but stop
+                 * descending into subdirs *)
+                else
+                  try
+                    xs.Xs.directory entry
+                    |> List.filter (fun x -> x <> "")
+                    |> map_tr (fun x -> dir ^ "/" ^ x)
+                  with _ -> []
               in
               (value_opt, subdirs)
             in
-            let rec ls_lR root acc dir -              let value_opt, subdirs = ls_l root dir in
-              let acc -                match value_opt with Some v -> v :: acc | None -> acc
-              in
-              List.fold_left (ls_lR root) acc subdirs
+            let rec ls_lR ?(depth = 512) root (quota, acc) dir +              if quota <= 0 then
+                (quota, acc) (* quota reached, stop listing/reading *)
+              else
+                let value_opt, subdirs = ls_l ~depth root dir in
+                let quota, acc +                  match value_opt with
+                  | Some v ->
+                      (quota - 1, v :: acc)
+                  | None ->
+                      (quota, acc)
+                in
+                let depth = depth - 1 in
+                List.fold_left (ls_lR ~depth root) (quota, acc) subdirs
             in
-            let guest_agent +            let quota = !Xenopsd.vm_xenstore_ls_lR_quota in
+            let quota, guest_agent                [
                 "drivers"; "attr"; "data"; "control"; "feature"; "xenserver/attr"
               ]
               |> List.fold_left
                    (ls_lR (Printf.sprintf "/local/domain/%d" di.Xenctrl.domid))
-                   []
-              |> map_tr (fun (k, v) -> (k, Xenops_utils.utf8_recode v))
+                   (quota, [])
+              |> fun (quota, acc) ->
+              (quota, map_tr (fun (k, v) -> (k, Xenops_utils.utf8_recode v)) acc)
             in
-            let xsdata_state +            let quota, xsdata_state                Domain.allowed_xsdata_prefixes
               |> List.fold_left
                    (ls_lR (Printf.sprintf "/local/domain/%d" di.Xenctrl.domid))
-                   []
+                   (quota, [])
             in
+            ( if quota <= 0 then
+                let path +                  Device_common.xenops_path_of_domain di.Xenctrl.domid
+                  ^ "/ls_lR_quota_reached"
+                in
+                try
+                  let (_ : string) = xs.Xs.read path in
+                  ()
+                with _ -> (
+                  debug "xenstore ls_lR quota reached for domid %d"
+                    di.Xenctrl.domid ;
+                  try xs.Xs.write path "t" with _ -> ()
+                )
+            ) ;
             let shadow_multiplier_target                if not di.Xenctrl.hvm_guest then
                 1.

["xsa354-5-ls_lR-limit-depth.patch" (application/octet-stream)]

From 244baaaeba0ce843917442f6697fb04702a3c66a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Edwin Török?= <edvin.torok@citrix.com>
Date: Wed, 4 Nov 2020 20:04:39 +0000
Subject: XSA-354: ls_lR: limit depth
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

We only want to read a few levels deep into the xenstore tree of the
guest.  Limit the depth at which we read keys to further reduce DoS
potential.

Signed-off-by: Edwin Török <edvin.torok@citrix.com>
Acked-by: Christian Lindig <christian.lindig@citrix.com>

diff --git a/xc/xenops_server_xen.ml b/xc/xenops_server_xen.ml
index 31a22186..32092deb 100644
--- a/xc/xenops_server_xen.ml
+++ b/xc/xenops_server_xen.ml
@@ -2628,10 +2628,19 @@ module VM = struct
             let quota = !Xenopsd.vm_xenstore_ls_lR_quota in
             let quota, guest_agent                [
-                "drivers"; "attr"; "data"; "control"; "feature"; "xenserver/attr"
+                ("drivers", 0)
+              ; ("attr", 3) (* attr/vif/0/ipv4/0, attr/eth0/ipv6/0/addr *)
+              ; ("data", 0)
+                (* in particular avoid data/volumes which contains many entries for each disk *)
+              ; ("control", 0)
+              ; ("feature/hotplug", 0)
+              ; ("xenserver/attr", 3) (* xenserver/attr/net-sriov-vf/0/ipv4/1 *)
               ]
               |> List.fold_left
-                   (ls_lR (Printf.sprintf "/local/domain/%d" di.Xenctrl.domid))
+                   (fun acc (dir, depth) ->
+                     ls_lR ~depth
+                       (Printf.sprintf "/local/domain/%d" di.Xenctrl.domid)
+                       acc dir)
                    (quota, [])
               |> fun (quota, acc) ->
               (quota, map_tr (fun (k, v) -> (k, Xenops_utils.utf8_recode v)) acc)

["xsa354-6-exclude-attr-os-hotfixes-from-ls_lR.patch" (application/octet-stream)]

From 8e8fe3e1895e9ccd510474b0c7e6032d3ba471c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Edwin Török?= <edvin.torok@citrix.com>
Date: Fri, 6 Nov 2020 10:38:36 +0000
Subject: XSA-354: exclude attr/os/hotfixes from ls_lR
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This is not needed by XAPI to determine the guest VM metrics field.  And
for old Windows OSes (e.g. WS12R2-x64) with many hotfixes this can hit
the xenopsd xenstore quota, breaking other functionality, because we
can't read the control/ entries anymore then.

Signed-off-by: Edwin Török <edvin.torok@citrix.com>
Acked-by: Christian Lindig <christian.lindig@citrix.com>

diff --git a/xc/xenops_server_xen.ml b/xc/xenops_server_xen.ml
index 32092deb..b80bf76b 100644
--- a/xc/xenops_server_xen.ml
+++ b/xc/xenops_server_xen.ml
@@ -2611,7 +2611,7 @@ module VM = struct
               (value_opt, subdirs)
             in
             let rec ls_lR ?(depth = 512) root (quota, acc) dir -              if quota <= 0 then
+              if quota <= 0 || dir = "attr/os/hotfixes" then
                 (quota, acc) (* quota reached, stop listing/reading *)
               else
                 let value_opt, subdirs = ls_l ~depth root dir in

["xsa354-7-read-important-xenstore-entries-first.patch" (application/octet-stream)]

From 1b55792875660f5c6ce3a54e0f44465dcc614eaa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Edwin Török?= <edvin.torok@citrix.com>
Date: Mon, 23 Nov 2020 11:00:35 +0000
Subject: XSA-354: read important xenstore entries first
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When the quota is hit some guest agent functionality might stop working.
Warn about this, and try to read the more important entries first as a
best-effort to keep it working (control, etc.).  Read data/ and vm-data/
last, so if the quota is hit there we can still do a clean shutdown of a
VM.

Of course a privileged user inside the guest can still use up entries
beyond the quota in one of the other xenstore subtrees and break guest
agent functionality, but if it is sufficiently privileged it could just
kill the guest agent, so that is expected.

Rename ls-lR-quota to guest-agent-quota.  Add comment explaining depth.

Periodically warn when the quota is exceeded.

Signed-off-by: Edwin Török <edvin.torok@citrix.com>
Acked-by: Christian Lindig <christian.lindig@citrix.com>

diff --git a/lib/xenopsd.ml b/lib/xenopsd.ml
index 94c55930..da02b79b 100644
--- a/lib/xenopsd.ml
+++ b/lib/xenopsd.ml
@@ -67,7 +67,9 @@ let numa_placement = ref false
 let numa_placement_strict = ref false

 (* O(N^2) operations, until we get a xenstore cache, so use a small number here *)
-let vm_xenstore_ls_lR_quota = ref 128
+let vm_guest_agent_xenstore_quota = ref 128
+
+let vm_guest_agent_xenstore_quota_warn_interval = ref 3600

 let options    [
@@ -172,10 +174,14 @@ let options      , (fun () -> string_of_bool !pci_quarantine)
     , "True if IOMMU contexts of PCI devices are needed to be placed in \
        quarantine" )
-  ; ( "vm-xenstore-ls-lR-quota"
-    , Arg.Set_int vm_xenstore_ls_lR_quota
-    , (fun () -> string_of_int !vm_xenstore_ls_lR_quota)
+  ; ( "vm-guest-agent-xenstore-quota"
+    , Arg.Set_int vm_guest_agent_xenstore_quota
+    , (fun () -> string_of_int !vm_guest_agent_xenstore_quota)
     , "Maximum entries in VM xenstore trees watched by xenopsd" )
+  ; ( "vm-guest-agent-xenstore-quota-warn-interval"
+    , Arg.Set_int vm_guest_agent_xenstore_quota_warn_interval
+    , (fun () -> string_of_int !vm_guest_agent_xenstore_quota_warn_interval)
+    , "How often to warn that a VM is still over its xenstore quota" )
   ]

 let path () = Filename.concat !sockets_path "xenopsd"
diff --git a/xc/xenops_server_xen.ml b/xc/xenops_server_xen.ml
index b80bf76b..d5205165 100644
--- a/xc/xenops_server_xen.ml
+++ b/xc/xenops_server_xen.ml
@@ -2625,16 +2625,18 @@ module VM = struct
                 let depth = depth - 1 in
                 List.fold_left (ls_lR ~depth root) (quota, acc) subdirs
             in
-            let quota = !Xenopsd.vm_xenstore_ls_lR_quota in
+            let quota = !Xenopsd.vm_guest_agent_xenstore_quota in
+            (* depth is the number of directories descended into,
+               keys at depth+1 are still read *)
             let quota, guest_agent                [
-                ("drivers", 0)
+                ("control", 0)
+              ; ("feature/hotplug", 0)
+              ; ("xenserver/attr", 3) (* xenserver/attr/net-sriov-vf/0/ipv4/1 *)
               ; ("attr", 3) (* attr/vif/0/ipv4/0, attr/eth0/ipv6/0/addr *)
+              ; ("drivers", 0)
               ; ("data", 0)
                 (* in particular avoid data/volumes which contains many entries for each disk *)
-              ; ("control", 0)
-              ; ("feature/hotplug", 0)
-              ; ("xenserver/attr", 3) (* xenserver/attr/net-sriov-vf/0/ipv4/1 *)
               ]
               |> List.fold_left
                    (fun acc (dir, depth) ->
@@ -2651,19 +2653,46 @@ module VM = struct
                    (ls_lR (Printf.sprintf "/local/domain/%d" di.Xenctrl.domid))
                    (quota, [])
             in
+            let path +              Device_common.xenops_path_of_domain di.Xenctrl.domid
+              ^ "/guest_agent_quota_reached"
+            in
+            (* we don't want the guest controlling how often we warn *)
+            let warned_path +              Device_common.get_private_path di.Xenctrl.domid
+              ^ "/guest_agent_quota_warned"
+            in
             ( if quota <= 0 then
-                let path -                  Device_common.xenops_path_of_domain di.Xenctrl.domid
-                  ^ "/ls_lR_quota_reached"
-                in
                 try
                   let (_ : string) = xs.Xs.read path in
-                  ()
+                  let now = Unix.gettimeofday () in
+                  let last +                    try float_of_string (xs.Xs.read warned_path) with _ -> 0.
+                  in
+                  if
+                    now -. last
+                    > float !Xenopsd.vm_guest_agent_xenstore_quota_warn_interval
+                  then (
+                    (* periodically warn if the quota is still exceeded *)
+                    xs.Xs.write warned_path (string_of_float now) ;
+                    warn
+                      "xenstore guest agent quota is still exceeded for domid \
+                       %d"
+                      di.Xenctrl.domid
+                  )
                 with _ -> (
-                  debug "xenstore ls_lR quota reached for domid %d"
+                  warn
+                    "xenstore guest agent quota reached for domid %d (VM \
+                     metrics and guest agent interaction might be broken, and \
+                     vm-data incomplete!)"
                     di.Xenctrl.domid ;
                   try xs.Xs.write path "t" with _ -> ()
                 )
+            else
+              try
+                let (_ : string) = xs.Xs.read path in
+                xs.Xs.rm path
+              with _ -> () (* do not RM the 'warned' path to prevent flood *)
             ) ;
             let shadow_multiplier_target                if not di.Xenctrl.hvm_guest then

["xsa354-8-refactor-attr-os-hotfixes-exclusion.patch" (application/octet-stream)]

From 96f9d3c1f733b471c842b08f930b341169f2af65 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Edwin Török?= <edvin.torok@citrix.com>
Date: Mon, 23 Nov 2020 15:50:29 +0000
Subject: XSA-354: refactor attr/os/hotfixes exclusion
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Edwin Török <edvin.torok@citrix.com>
Acked-by: Christian Lindig <christian.lindig@citrix.com>

diff --git a/xc/xenops_server_xen.ml b/xc/xenops_server_xen.ml
index d5205165..c805c750 100644
--- a/xc/xenops_server_xen.ml
+++ b/xc/xenops_server_xen.ml
@@ -25,6 +25,7 @@ module D = Debug.Make (struct let name = service_name end)

 open D
 module RRDD = Rrd_client.Client
+module StringSet = Set.Make (String)

 let finally = Xapi_stdext_pervasives.Pervasiveext.finally

@@ -2610,8 +2611,9 @@ module VM = struct
               in
               (value_opt, subdirs)
             in
-            let rec ls_lR ?(depth = 512) root (quota, acc) dir -              if quota <= 0 || \
dir = "attr/os/hotfixes" then +            let rec ls_lR ?(excludes = StringSet.empty) ?(depth \
= 512) root +                (quota, acc) dir +              if quota <= 0 || StringSet.mem dir \
excludes then  (quota, acc) (* quota reached, stop listing/reading *)
               else
                 let value_opt, subdirs = ls_l ~depth root dir in
@@ -2623,24 +2625,29 @@ module VM = struct
                       (quota, acc)
                 in
                 let depth = depth - 1 in
-                List.fold_left (ls_lR ~depth root) (quota, acc) subdirs
+                List.fold_left
+                  (ls_lR ~excludes ~depth root)
+                  (quota, acc) subdirs
             in
             let quota = !Xenopsd.vm_guest_agent_xenstore_quota in
             (* depth is the number of directories descended into,
                keys at depth+1 are still read *)
             let quota, guest_agent                [
-                ("control", 0)
-              ; ("feature/hotplug", 0)
-              ; ("xenserver/attr", 3) (* xenserver/attr/net-sriov-vf/0/ipv4/1 *)
-              ; ("attr", 3) (* attr/vif/0/ipv4/0, attr/eth0/ipv6/0/addr *)
-              ; ("drivers", 0)
-              ; ("data", 0)
+                ("control", None, 0)
+              ; ("feature/hotplug", None, 0)
+              ; ("xenserver/attr", None, 3)
+                (* xenserver/attr/net-sriov-vf/0/ipv4/1 *)
+              ; ("attr", Some (StringSet.singleton "attr/os/hotfixes"), 3)
+                (* attr/vif/0/ipv4/0, attr/eth0/ipv6/0/addr,
+                   and exclude hotfixes which can exceed the quota on their own *)
+              ; ("drivers", None, 0)
+              ; ("data", None, 0)
                 (* in particular avoid data/volumes which contains many entries for each disk \
*)  ]
               |> List.fold_left
-                   (fun acc (dir, depth) ->
-                     ls_lR ~depth
+                   (fun acc (dir, excludes, depth) ->
+                     ls_lR ?excludes ~depth
                        (Printf.sprintf "/local/domain/%d" di.Xenctrl.domid)
                        acc dir)
                    (quota, [])



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic